kalarm

recurrenceedit.cpp
1 /*
2  * recurrenceedit.cpp - widget to edit the event's recurrence definition
3  * Program: kalarm
4  * Copyright © 2002-2008 by David Jarvie <djarvie@kde.org>
5  *
6  * Based originally on KOrganizer module koeditorrecurrence.cpp,
7  * Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #include "kalarm.h"
25 
26 #include <tqtooltip.h>
27 #include <tqlayout.h>
28 #include <tqvbox.h>
29 #include <tqwidgetstack.h>
30 #include <tqlistbox.h>
31 #include <tqframe.h>
32 #include <tqlabel.h>
33 #include <tqpushbutton.h>
34 #include <tqlineedit.h>
35 #include <tqwhatsthis.h>
36 
37 #include <tdeglobal.h>
38 #include <tdelocale.h>
39 #include <kcalendarsystem.h>
40 #include <kiconloader.h>
41 #include <kdialog.h>
42 #include <tdemessagebox.h>
43 #include <kdebug.h>
44 
45 #include <libkcal/event.h>
46 
47 #include "alarmevent.h"
48 #include "alarmtimewidget.h"
49 #include "checkbox.h"
50 #include "combobox.h"
51 #include "dateedit.h"
52 #include "functions.h"
53 #include "kalarmapp.h"
54 #include "karecurrence.h"
55 #include "preferences.h"
56 #include "radiobutton.h"
57 #include "repetition.h"
58 #include "spinbox.h"
59 #include "timeedit.h"
60 #include "timespinbox.h"
61 #include "buttongroup.h"
62 using namespace KCal;
63 
64 #include "recurrenceedit.moc"
65 #include "recurrenceeditprivate.moc"
66 
67 // Collect these widget labels together to ensure consistent wording and
68 // translations across different modules.
69 TQString RecurrenceEdit::i18n_Norecur() { return i18n("No recurrence"); }
70 TQString RecurrenceEdit::i18n_NoRecur() { return i18n("No Recurrence"); }
71 TQString RecurrenceEdit::i18n_AtLogin() { return i18n("At Login"); }
72 TQString RecurrenceEdit::i18n_l_Atlogin() { return i18n("At &login"); }
73 TQString RecurrenceEdit::i18n_HourlyMinutely() { return i18n("Hourly/Minutely"); }
74 TQString RecurrenceEdit::i18n_u_HourlyMinutely() { return i18n("Ho&urly/Minutely"); }
75 TQString RecurrenceEdit::i18n_Daily() { return i18n("Daily"); }
76 TQString RecurrenceEdit::i18n_d_Daily() { return i18n("&Daily"); }
77 TQString RecurrenceEdit::i18n_Weekly() { return i18n("Weekly"); }
78 TQString RecurrenceEdit::i18n_w_Weekly() { return i18n("&Weekly"); }
79 TQString RecurrenceEdit::i18n_Monthly() { return i18n("Monthly"); }
80 TQString RecurrenceEdit::i18n_m_Monthly() { return i18n("&Monthly"); }
81 TQString RecurrenceEdit::i18n_Yearly() { return i18n("Yearly"); }
82 TQString RecurrenceEdit::i18n_y_Yearly() { return i18n("&Yearly"); }
83 
84 
85 RecurrenceEdit::RecurrenceEdit(bool readOnly, TQWidget* parent, const char* name)
86  : TQFrame(parent, name),
87  mRule(0),
88  mRuleButtonType(INVALID_RECUR),
89  mDailyShown(false),
90  mWeeklyShown(false),
91  mMonthlyShown(false),
92  mYearlyShown(false),
93  mNoEmitTypeChanged(true),
94  mReadOnly(readOnly)
95 {
96  TQBoxLayout* layout;
97  TQVBoxLayout* topLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint());
98 
99  /* Create the recurrence rule Group box which holds the recurrence period
100  * selection buttons, and the weekly, monthly and yearly recurrence rule
101  * frames which specify options individual to each of these distinct
102  * sections of the recurrence rule. Each frame is made visible by the
103  * selection of its corresponding radio button.
104  */
105 
106  TQGroupBox* recurGroup = new TQGroupBox(1, TQt::Vertical, i18n("Recurrence Rule"), this, "recurGroup");
107  topLayout->addWidget(recurGroup);
108  TQFrame* ruleFrame = new TQFrame(recurGroup, "ruleFrame");
109  layout = new TQVBoxLayout(ruleFrame, 0);
110  layout->addSpacing(KDialog::spacingHint()/2);
111 
112  layout = new TQHBoxLayout(layout, 0);
113  TQBoxLayout* lay = new TQVBoxLayout(layout, 0);
114  mRuleButtonGroup = new ButtonGroup(1, TQt::Horizontal, ruleFrame);
115  mRuleButtonGroup->setInsideMargin(0);
116  mRuleButtonGroup->setFrameStyle(TQFrame::NoFrame);
117  lay->addWidget(mRuleButtonGroup);
118  lay->addStretch(); // top-adjust the interval radio buttons
119  connect(mRuleButtonGroup, TQ_SIGNAL(buttonSet(int)), TQ_SLOT(periodClicked(int)));
120 
121  mNoneButton = new RadioButton(i18n_Norecur(), mRuleButtonGroup);
122  mNoneButton->setFixedSize(mNoneButton->sizeHint());
123  mNoneButton->setReadOnly(mReadOnly);
124  TQWhatsThis::add(mNoneButton, i18n("Do not repeat the alarm"));
125 
126  mAtLoginButton = new RadioButton(i18n_l_Atlogin(), mRuleButtonGroup);
127  mAtLoginButton->setFixedSize(mAtLoginButton->sizeHint());
128  mAtLoginButton->setReadOnly(mReadOnly);
129  TQWhatsThis::add(mAtLoginButton,
130  i18n("Trigger the alarm at the specified date/time and at every login until then.\n"
131  "Note that it will also be triggered any time the alarm daemon is restarted."));
132 
133  mSubDailyButton = new RadioButton(i18n_u_HourlyMinutely(), mRuleButtonGroup);
134  mSubDailyButton->setFixedSize(mSubDailyButton->sizeHint());
135  mSubDailyButton->setReadOnly(mReadOnly);
136  TQWhatsThis::add(mSubDailyButton,
137  i18n("Repeat the alarm at hourly/minutely intervals"));
138 
139  mDailyButton = new RadioButton(i18n_d_Daily(), mRuleButtonGroup);
140  mDailyButton->setFixedSize(mDailyButton->sizeHint());
141  mDailyButton->setReadOnly(mReadOnly);
142  TQWhatsThis::add(mDailyButton,
143  i18n("Repeat the alarm at daily intervals"));
144 
145  mWeeklyButton = new RadioButton(i18n_w_Weekly(), mRuleButtonGroup);
146  mWeeklyButton->setFixedSize(mWeeklyButton->sizeHint());
147  mWeeklyButton->setReadOnly(mReadOnly);
148  TQWhatsThis::add(mWeeklyButton,
149  i18n("Repeat the alarm at weekly intervals"));
150 
151  mMonthlyButton = new RadioButton(i18n_m_Monthly(), mRuleButtonGroup);
152  mMonthlyButton->setFixedSize(mMonthlyButton->sizeHint());
153  mMonthlyButton->setReadOnly(mReadOnly);
154  TQWhatsThis::add(mMonthlyButton,
155  i18n("Repeat the alarm at monthly intervals"));
156 
157  mYearlyButton = new RadioButton(i18n_y_Yearly(), mRuleButtonGroup);
158  mYearlyButton->setFixedSize(mYearlyButton->sizeHint());
159  mYearlyButton->setReadOnly(mReadOnly);
160  TQWhatsThis::add(mYearlyButton,
161  i18n("Repeat the alarm at annual intervals"));
162 
163  mNoneButtonId = mRuleButtonGroup->id(mNoneButton);
164  mAtLoginButtonId = mRuleButtonGroup->id(mAtLoginButton);
165  mSubDailyButtonId = mRuleButtonGroup->id(mSubDailyButton);
166  mDailyButtonId = mRuleButtonGroup->id(mDailyButton);
167  mWeeklyButtonId = mRuleButtonGroup->id(mWeeklyButton);
168  mMonthlyButtonId = mRuleButtonGroup->id(mMonthlyButton);
169  mYearlyButtonId = mRuleButtonGroup->id(mYearlyButton);
170 
171  // Sub-repetition button
172  mSubRepetition = new RepetitionButton(i18n("Sub-Repetition"), true, ruleFrame);
173  mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
174  mSubRepetition->setReadOnly(mReadOnly);
175  connect(mSubRepetition, TQ_SIGNAL(needsInitialisation()), TQ_SIGNAL(repeatNeedsInitialisation()));
176  connect(mSubRepetition, TQ_SIGNAL(changed()), TQ_SIGNAL(frequencyChanged()));
177  TQWhatsThis::add(mSubRepetition, i18n("Set up a repetition within the recurrence, to trigger the alarm multiple times each time the recurrence is due."));
178  lay->addSpacing(KDialog::spacingHint());
179  lay->addWidget(mSubRepetition);
180 
181  lay = new TQVBoxLayout(layout);
182 
183  lay->addStretch();
184  layout = new TQHBoxLayout(lay);
185 
186  layout->addSpacing(KDialog::marginHint());
187  TQFrame* divider = new TQFrame(ruleFrame);
188  divider->setFrameStyle(TQFrame::VLine | TQFrame::Sunken);
189  layout->addWidget(divider);
190  layout->addSpacing(KDialog::marginHint());
191 
192  mNoRule = new NoRule(ruleFrame, "noFrame");
193  mSubDailyRule = new SubDailyRule(mReadOnly, ruleFrame, "subdayFrame");
194  mDailyRule = new DailyRule(mReadOnly, ruleFrame, "dayFrame");
195  mWeeklyRule = new WeeklyRule(mReadOnly, ruleFrame, "weekFrame");
196  mMonthlyRule = new MonthlyRule(mReadOnly, ruleFrame, "monthFrame");
197  mYearlyRule = new YearlyRule(mReadOnly, ruleFrame, "yearFrame");
198 
199  connect(mSubDailyRule, TQ_SIGNAL(frequencyChanged()), this, TQ_SIGNAL(frequencyChanged()));
200  connect(mDailyRule, TQ_SIGNAL(frequencyChanged()), this, TQ_SIGNAL(frequencyChanged()));
201  connect(mWeeklyRule, TQ_SIGNAL(frequencyChanged()), this, TQ_SIGNAL(frequencyChanged()));
202  connect(mMonthlyRule, TQ_SIGNAL(frequencyChanged()), this, TQ_SIGNAL(frequencyChanged()));
203  connect(mYearlyRule, TQ_SIGNAL(frequencyChanged()), this, TQ_SIGNAL(frequencyChanged()));
204 
205  mRuleStack = new TQWidgetStack(ruleFrame);
206  layout->addWidget(mRuleStack);
207  layout->addStretch(1);
208  mRuleStack->addWidget(mNoRule, 0);
209  mRuleStack->addWidget(mSubDailyRule, 1);
210  mRuleStack->addWidget(mDailyRule, 2);
211  mRuleStack->addWidget(mWeeklyRule, 3);
212  mRuleStack->addWidget(mMonthlyRule, 4);
213  mRuleStack->addWidget(mYearlyRule, 5);
214  layout->addSpacing(KDialog::marginHint());
215 
216  // Create the recurrence range group which contains the controls
217  // which specify how long the recurrence is to last.
218 
219  mRangeButtonGroup = new ButtonGroup(i18n("Recurrence End"), this, "mRangeButtonGroup");
220  connect(mRangeButtonGroup, TQ_SIGNAL(buttonSet(int)), TQ_SLOT(rangeTypeClicked()));
221  topLayout->addWidget(mRangeButtonGroup);
222 
223  TQVBoxLayout* vlayout = new TQVBoxLayout(mRangeButtonGroup, KDialog::marginHint(), KDialog::spacingHint());
224  vlayout->addSpacing(fontMetrics().lineSpacing()/2);
225  mNoEndDateButton = new RadioButton(i18n("No &end"), mRangeButtonGroup);
226  mNoEndDateButton->setFixedSize(mNoEndDateButton->sizeHint());
227  mNoEndDateButton->setReadOnly(mReadOnly);
228  TQWhatsThis::add(mNoEndDateButton, i18n("Repeat the alarm indefinitely"));
229  vlayout->addWidget(mNoEndDateButton, 1, TQt::AlignAuto);
230  TQSize size = mNoEndDateButton->size();
231 
232  layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
233  mRepeatCountButton = new RadioButton(i18n("End a&fter:"), mRangeButtonGroup);
234  mRepeatCountButton->setReadOnly(mReadOnly);
235  TQWhatsThis::add(mRepeatCountButton,
236  i18n("Repeat the alarm for the number of times specified"));
237  mRepeatCountEntry = new SpinBox(1, 9999, 1, mRangeButtonGroup);
238  mRepeatCountEntry->setFixedSize(mRepeatCountEntry->sizeHint());
239  mRepeatCountEntry->setLineShiftStep(10);
240  mRepeatCountEntry->setSelectOnStep(false);
241  mRepeatCountEntry->setReadOnly(mReadOnly);
242  connect(mRepeatCountEntry, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(repeatCountChanged(int)));
243  TQWhatsThis::add(mRepeatCountEntry,
244  i18n("Enter the total number of times to trigger the alarm"));
245  mRepeatCountButton->setFocusWidget(mRepeatCountEntry);
246  mRepeatCountLabel = new TQLabel(i18n("occurrence(s)"), mRangeButtonGroup);
247  mRepeatCountLabel->setFixedSize(mRepeatCountLabel->sizeHint());
248  layout->addWidget(mRepeatCountButton);
249  layout->addSpacing(KDialog::spacingHint());
250  layout->addWidget(mRepeatCountEntry);
251  layout->addWidget(mRepeatCountLabel);
252  layout->addStretch();
253  size = size.expandedTo(mRepeatCountButton->sizeHint());
254 
255  layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
256  mEndDateButton = new RadioButton(i18n("End &by:"), mRangeButtonGroup);
257  mEndDateButton->setReadOnly(mReadOnly);
258  TQWhatsThis::add(mEndDateButton,
259  i18n("Repeat the alarm until the date/time specified.\n\n"
260  "Note: This applies to the main recurrence only. It does not limit any sub-repetition which will occur regardless after the last main recurrence."));
261  mEndDateEdit = new DateEdit(mRangeButtonGroup);
262  mEndDateEdit->setFixedSize(mEndDateEdit->sizeHint());
263  mEndDateEdit->setReadOnly(mReadOnly);
264  TQWhatsThis::add(mEndDateEdit,
265  i18n("Enter the last date to repeat the alarm"));
266  mEndDateButton->setFocusWidget(mEndDateEdit);
267  mEndTimeEdit = new TimeEdit(mRangeButtonGroup);
268  mEndTimeEdit->setFixedSize(mEndTimeEdit->sizeHint());
269  mEndTimeEdit->setReadOnly(mReadOnly);
270  static const TQString lastTimeText = i18n("Enter the last time to repeat the alarm.");
271  TQWhatsThis::add(mEndTimeEdit, TQString("%1\n\n%2").arg(lastTimeText).arg(TimeSpinBox::shiftWhatsThis()));
272  mEndAnyTimeCheckBox = new CheckBox(i18n("Any time"), mRangeButtonGroup);
273  mEndAnyTimeCheckBox->setFixedSize(mEndAnyTimeCheckBox->sizeHint());
274  mEndAnyTimeCheckBox->setReadOnly(mReadOnly);
275  connect(mEndAnyTimeCheckBox, TQ_SIGNAL(toggled(bool)), TQ_SLOT(slotAnyTimeToggled(bool)));
276  TQWhatsThis::add(mEndAnyTimeCheckBox,
277  i18n("Stop repeating the alarm after your first login on or after the specified end date"));
278  layout->addWidget(mEndDateButton);
279  layout->addSpacing(KDialog::spacingHint());
280  layout->addWidget(mEndDateEdit);
281  layout->addWidget(mEndTimeEdit);
282  layout->addWidget(mEndAnyTimeCheckBox);
283  layout->addStretch();
284  size = size.expandedTo(mEndDateButton->sizeHint());
285 
286  // Line up the widgets to the right of the radio buttons
287  mRepeatCountButton->setFixedSize(size);
288  mEndDateButton->setFixedSize(size);
289 
290  // Create the exceptions group which specifies dates to be excluded
291  // from the recurrence.
292 
293  mExceptionGroup = new TQGroupBox(i18n("E&xceptions"), this, "mExceptionGroup");
294  topLayout->addWidget(mExceptionGroup);
295  topLayout->setStretchFactor(mExceptionGroup, 2);
296  vlayout = new TQVBoxLayout(mExceptionGroup, KDialog::marginHint(), KDialog::spacingHint());
297  vlayout->addSpacing(fontMetrics().lineSpacing()/2);
298  layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
299  vlayout = new TQVBoxLayout(layout);
300 
301  mExceptionDateList = new TQListBox(mExceptionGroup);
302  mExceptionDateList->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding));
303  connect(mExceptionDateList, TQ_SIGNAL(selectionChanged()), TQ_SLOT(enableExceptionButtons()));
304  TQWhatsThis::add(mExceptionDateList,
305  i18n("The list of exceptions, i.e. dates/times excluded from the recurrence"));
306  vlayout->addWidget(mExceptionDateList);
307 
308  if (mReadOnly)
309  {
310  mExceptionDateEdit = 0;
311  mChangeExceptionButton = 0;
312  mDeleteExceptionButton = 0;
313  }
314  else
315  {
316  vlayout = new TQVBoxLayout(layout);
317  mExceptionDateEdit = new DateEdit(mExceptionGroup);
318  mExceptionDateEdit->setFixedSize(mExceptionDateEdit->sizeHint());
319  mExceptionDateEdit->setDate(TQDate::currentDate());
320  TQWhatsThis::add(mExceptionDateEdit,
321  i18n("Enter a date to insert in the exceptions list. "
322  "Use in conjunction with the Add or Change button below."));
323  vlayout->addWidget(mExceptionDateEdit);
324 
325  layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
326  TQPushButton* button = new TQPushButton(i18n("Add"), mExceptionGroup);
327  button->setFixedSize(button->sizeHint());
328  connect(button, TQ_SIGNAL(clicked()), TQ_SLOT(addException()));
329  TQWhatsThis::add(button,
330  i18n("Add the date entered above to the exceptions list"));
331  layout->addWidget(button);
332 
333  mChangeExceptionButton = new TQPushButton(i18n("Change"), mExceptionGroup);
334  mChangeExceptionButton->setFixedSize(mChangeExceptionButton->sizeHint());
335  connect(mChangeExceptionButton, TQ_SIGNAL(clicked()), TQ_SLOT(changeException()));
336  TQWhatsThis::add(mChangeExceptionButton,
337  i18n("Replace the currently highlighted item in the exceptions list with the date entered above"));
338  layout->addWidget(mChangeExceptionButton);
339 
340  mDeleteExceptionButton = new TQPushButton(i18n("Delete"), mExceptionGroup);
341  mDeleteExceptionButton->setFixedSize(mDeleteExceptionButton->sizeHint());
342  connect(mDeleteExceptionButton, TQ_SIGNAL(clicked()), TQ_SLOT(deleteException()));
343  TQWhatsThis::add(mDeleteExceptionButton,
344  i18n("Remove the currently highlighted item from the exceptions list"));
345  layout->addWidget(mDeleteExceptionButton);
346  }
347 
348  mNoEmitTypeChanged = false;
349 }
350 
351 /******************************************************************************
352  * Verify the consistency of the entered data.
353  * Reply = widget to receive focus on error, or 0 if no error.
354  */
355 TQWidget* RecurrenceEdit::checkData(const TQDateTime& startDateTime, TQString& errorMessage) const
356 {
357  if (mAtLoginButton->isOn())
358  return 0;
359  const_cast<RecurrenceEdit*>(this)->mCurrStartDateTime = startDateTime;
360  if (mEndDateButton->isChecked())
361  {
362  TQWidget* errWidget = 0;
363  bool noTime = !mEndTimeEdit->isEnabled();
364  TQDate endDate = mEndDateEdit->date();
365  if (endDate < startDateTime.date())
366  errWidget = mEndDateEdit;
367  else if (!noTime && TQDateTime(endDate, mEndTimeEdit->time()) < startDateTime)
368  errWidget = mEndTimeEdit;
369  if (errWidget)
370  {
371  errorMessage = noTime
372  ? i18n("End date is earlier than start date")
373  : i18n("End date/time is earlier than start date/time");
374  return errWidget;
375  }
376  }
377  if (!mRule)
378  return 0;
379  return mRule->validate(errorMessage);
380 }
381 
382 /******************************************************************************
383  * Called when a recurrence period radio button is clicked.
384  */
385 void RecurrenceEdit::periodClicked(int id)
386 {
387  RepeatType oldType = mRuleButtonType;
388  bool none = (id == mNoneButtonId);
389  bool atLogin = (id == mAtLoginButtonId);
390  bool subdaily = (id == mSubDailyButtonId);
391  if (none)
392  {
393  mRule = 0;
394  mRuleButtonType = NO_RECUR;
395  }
396  else if (atLogin)
397  {
398  mRule = 0;
399  mRuleButtonType = AT_LOGIN;
400  mRangeButtonGroup->setButton(mRangeButtonGroup->id(mEndDateButton));
401  }
402  else if (subdaily)
403  {
404  mRule = mSubDailyRule;
405  mRuleButtonType = SUBDAILY;
406  }
407  else if (id == mDailyButtonId)
408  {
409  mRule = mDailyRule;
410  mRuleButtonType = DAILY;
411  mDailyShown = true;
412  }
413  else if (id == mWeeklyButtonId)
414  {
415  mRule = mWeeklyRule;
416  mRuleButtonType = WEEKLY;
417  mWeeklyShown = true;
418  }
419  else if (id == mMonthlyButtonId)
420  {
421  mRule = mMonthlyRule;
422  mRuleButtonType = MONTHLY;
423  mMonthlyShown = true;
424  }
425  else if (id == mYearlyButtonId)
426  {
427  mRule = mYearlyRule;
428  mRuleButtonType = ANNUAL;
429  mYearlyShown = true;
430  }
431  else
432  return;
433 
434  if (mRuleButtonType != oldType)
435  {
436  mRuleStack->raiseWidget(mRule ? mRule : mNoRule);
437  if (oldType == NO_RECUR || none)
438  mRangeButtonGroup->setEnabled(!none);
439  mExceptionGroup->setEnabled(!(none || atLogin));
440  mEndAnyTimeCheckBox->setEnabled(atLogin);
441  if (!none)
442  {
443  mNoEndDateButton->setEnabled(!atLogin);
444  mRepeatCountButton->setEnabled(!atLogin);
445  }
446  rangeTypeClicked();
447  mSubRepetition->setEnabled(!(none || atLogin));
448  if (!mNoEmitTypeChanged)
449  emit typeChanged(mRuleButtonType);
450  }
451 }
452 
453 void RecurrenceEdit::slotAnyTimeToggled(bool on)
454 {
455  TQButton* button = mRuleButtonGroup->selected();
456  mEndTimeEdit->setEnabled((button == mAtLoginButton && !on)
457  || (button == mSubDailyButton && mEndDateButton->isChecked()));
458 }
459 
460 /******************************************************************************
461  * Called when a recurrence range type radio button is clicked.
462  */
463 void RecurrenceEdit::rangeTypeClicked()
464 {
465  bool endDate = mEndDateButton->isOn();
466  mEndDateEdit->setEnabled(endDate);
467  mEndTimeEdit->setEnabled(endDate
468  && ((mAtLoginButton->isOn() && !mEndAnyTimeCheckBox->isChecked())
469  || mSubDailyButton->isOn()));
470  bool repeatCount = mRepeatCountButton->isOn();
471  mRepeatCountEntry->setEnabled(repeatCount);
472  mRepeatCountLabel->setEnabled(repeatCount);
473 }
474 
475 void RecurrenceEdit::showEvent(TQShowEvent*)
476 {
477  if (mRule)
478  mRule->setFrequencyFocus();
479  else
480  mRuleButtonGroup->selected()->setFocus();
481  emit shown();
482 }
483 
484  /******************************************************************************
485 * Return the sub-repetition count within the recurrence, i.e. the number of
486 * repetitions after the main recurrence.
487 */
488 int RecurrenceEdit::subRepeatCount(int* subRepeatInterval) const
489 {
490  int count = (mRuleButtonType >= SUBDAILY) ? mSubRepetition->count() : 0;
491  if (subRepeatInterval)
492  *subRepeatInterval = count ? mSubRepetition->interval() : 0;
493  return count;
494 }
495 
496 /******************************************************************************
497 * Called when the Sub-Repetition button has been pressed to display the
498 * sub-repetition dialog.
499 * Alarm repetition has the following restrictions:
500 * 1) Not allowed for a repeat-at-login alarm
501 * 2) For a date-only alarm, the repeat interval must be a whole number of days.
502 * 3) The overall repeat duration must be less than the recurrence interval.
503 */
504 void RecurrenceEdit::setSubRepetition(int reminderMinutes, bool dateOnly)
505 {
506  int maxDuration;
507  switch (mRuleButtonType)
508  {
509  case RecurrenceEdit::NO_RECUR:
510  case RecurrenceEdit::AT_LOGIN: // alarm repeat not allowed
511  maxDuration = 0;
512  break;
513  default: // repeat duration must be less than recurrence interval
514  {
515  KAEvent event;
516  updateEvent(event, false);
517  maxDuration = event.longestRecurrenceInterval() - reminderMinutes - 1;
518  break;
519  }
520  }
521  mSubRepetition->initialise(mSubRepetition->interval(), mSubRepetition->count(), dateOnly, maxDuration);
522  mSubRepetition->setEnabled(mRuleButtonType >= SUBDAILY && maxDuration);
523 }
524 
525 /******************************************************************************
526 * Activate the sub-repetition dialog.
527 */
528 void RecurrenceEdit::activateSubRepetition()
529 {
530  mSubRepetition->activate();
531 }
532 
533 /******************************************************************************
534 * For weekly, monthly and yearly recurrence, checks that the specified date
535 * matches the days allowed. For the other recurrence simply return true.
536 */
537 bool RecurrenceEdit::validateDate(const DateTime &date) const
538 {
539  if (mRuleButtonType == RecurrenceEdit::DAILY)
540  {
541  TQBitArray selectedDays = mDailyRule->days();
542  if (!selectedDays[date.date().dayOfWeek()-1])
543  return false;
544  }
545  else if (mRuleButtonType == RecurrenceEdit::WEEKLY)
546  {
547  TQBitArray selectedDays = mWeeklyRule->days();
548  if (!selectedDays[date.date().dayOfWeek()-1])
549  return false;
550  }
551  else if (mRuleButtonType == RecurrenceEdit::MONTHLY)
552  {
553  if (mMonthlyRule->type() == MonthYearRule::DATE)
554  {
555  // on the nth day of the month
556  int comboDate = mMonthlyRule->date();
557  if ((comboDate > 0 && date.date().day() != comboDate) ||
558  (comboDate <=0 && date.date().day() != date.date().daysInMonth()))
559  return false;
560  }
561  else
562  {
563  // on the nth weekday (i.e. Monday) of the month
564  if (date.date().dayOfWeek() != mMonthlyRule->dayOfWeek())
565  return false;
566 
567  int monthDay = date.date().day();
568  int weekNum = mMonthlyRule->week();
569  int minDay = 0, maxDay = 0;
570  if (weekNum > 0 )
571  {
572  minDay = (weekNum-1) * 7;
573  maxDay = weekNum * 7;
574  }
575  else if (weekNum < 0)
576  {
577  int dim = date.date().daysInMonth();
578  minDay = dim + weekNum * 7;
579  maxDay = dim + (weekNum+1) * 7;
580  }
581  if (monthDay <= minDay || monthDay > maxDay)
582  return false;
583  }
584  }
585  else if (mRuleButtonType == RecurrenceEdit::ANNUAL)
586  {
587  TQValueList<int> months = mYearlyRule->months();
588  if (!months.contains(date.date().month()))
589  return false;
590 
591  if (mYearlyRule->type() == MonthYearRule::DATE)
592  {
593  // on the nth day of the month
594  int comboDate = mYearlyRule->date();
595  if ((comboDate > 0 && date.date().day() != comboDate) ||
596  (comboDate <=0 && date.date().day() != date.date().daysInMonth()))
597  return false;
598  }
599  else
600  {
601  // on the nth weekday (i.e. Monday) of the month
602  if (date.date().dayOfWeek() != mYearlyRule->dayOfWeek())
603  return false;
604 
605  int monthDay = date.date().day();
606  int weekNum = mYearlyRule->week();
607  int minDay = 0, maxDay = 0;
608  if (weekNum > 0 )
609  {
610  minDay = (weekNum-1) * 7;
611  maxDay = weekNum * 7;
612  }
613  else if (weekNum < 0)
614  {
615  int dim = date.date().daysInMonth();
616  minDay = dim + weekNum * 7;
617  maxDay = dim + (weekNum+1) * 7;
618  }
619  if (monthDay <= minDay || monthDay > maxDay)
620  return false;
621  }
622  }
623  return true;
624 }
625 
626 /******************************************************************************
627  * Called when the value of the repeat count field changes, to reset the
628  * minimum value to 1 if the value was 0.
629  */
630 void RecurrenceEdit::repeatCountChanged(int value)
631 {
632  if (value > 0 && mRepeatCountEntry->minValue() == 0)
633  mRepeatCountEntry->setMinValue(1);
634 }
635 
636 /******************************************************************************
637  * Add the date entered in the exception date edit control to the list of
638  * exception dates.
639  */
640 void RecurrenceEdit::addException()
641 {
642  if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
643  return;
644  TQDate date = mExceptionDateEdit->date();
645  TQValueList<TQDate>::Iterator it;
646  int index = 0;
647  bool insert = true;
648  for (it = mExceptionDates.begin(); it != mExceptionDates.end(); ++index, ++it)
649  {
650  if (date <= *it)
651  {
652  insert = (date != *it);
653  break;
654  }
655  }
656  if (insert)
657  {
658  mExceptionDates.insert(it, date);
659  mExceptionDateList->insertItem(TDEGlobal::locale()->formatDate(date), index);
660  }
661  mExceptionDateList->setCurrentItem(index);
662  enableExceptionButtons();
663 }
664 
665 /******************************************************************************
666  * Change the currently highlighted exception date to that entered in the
667  * exception date edit control.
668  */
669 void RecurrenceEdit::changeException()
670 {
671  if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
672  return;
673  int index = mExceptionDateList->currentItem();
674  if (index >= 0 && mExceptionDateList->isSelected(index))
675  {
676  TQDate olddate = mExceptionDates[index];
677  TQDate newdate = mExceptionDateEdit->date();
678  if (newdate != olddate)
679  {
680  mExceptionDates.remove(mExceptionDates.at(index));
681  mExceptionDateList->removeItem(index);
682  addException();
683  }
684  }
685 }
686 
687 /******************************************************************************
688  * Delete the currently highlighted exception date.
689  */
690 void RecurrenceEdit::deleteException()
691 {
692  int index = mExceptionDateList->currentItem();
693  if (index >= 0 && mExceptionDateList->isSelected(index))
694  {
695  mExceptionDates.remove(mExceptionDates.at(index));
696  mExceptionDateList->removeItem(index);
697  enableExceptionButtons();
698  }
699 }
700 
701 /******************************************************************************
702  * Enable/disable the exception group buttons according to whether any item is
703  * selected in the exceptions listbox.
704  */
705 void RecurrenceEdit::enableExceptionButtons()
706 {
707  int index = mExceptionDateList->currentItem();
708  bool enable = (index >= 0 && mExceptionDateList->isSelected(index));
709  if (mDeleteExceptionButton)
710  mDeleteExceptionButton->setEnabled(enable);
711  if (mChangeExceptionButton)
712  mChangeExceptionButton->setEnabled(enable);
713 
714  // Prevent the exceptions list box receiving keyboard focus is it's empty
715  mExceptionDateList->setFocusPolicy(mExceptionDateList->count() ? TQWidget::WheelFocus : TQWidget::NoFocus);
716 }
717 
718 /******************************************************************************
719  * Notify this instance of a change in the alarm start date.
720  */
721 void RecurrenceEdit::setStartDate(const TQDate& start, const TQDate& today)
722 {
723  if (!mReadOnly)
724  {
725  setRuleDefaults(start);
726  if (start < today)
727  {
728  mEndDateEdit->setMinDate(today);
729  if (mExceptionDateEdit)
730  mExceptionDateEdit->setMinDate(today);
731  }
732  else
733  {
734  const TQString startString = i18n("Date cannot be earlier than start date", "start date");
735  mEndDateEdit->setMinDate(start, startString);
736  if (mExceptionDateEdit)
737  mExceptionDateEdit->setMinDate(start, startString);
738  }
739  }
740 }
741 
742 /******************************************************************************
743  * Specify the default recurrence end date.
744  */
745 void RecurrenceEdit::setDefaultEndDate(const TQDate& end)
746 {
747  if (!mEndDateButton->isOn())
748  mEndDateEdit->setDate(end);
749 }
750 
751 void RecurrenceEdit::setEndDateTime(const DateTime& end)
752 {
753  mEndDateEdit->setDate(end.date());
754  mEndTimeEdit->setValue(end.time());
755  mEndTimeEdit->setEnabled(!end.isDateOnly());
756  mEndAnyTimeCheckBox->setChecked(end.isDateOnly());
757 }
758 
759 DateTime RecurrenceEdit::endDateTime() const
760 {
761  if (mRuleButtonGroup->selected() == mAtLoginButton && mEndAnyTimeCheckBox->isChecked())
762  return DateTime(mEndDateEdit->date());
763  return DateTime(mEndDateEdit->date(), mEndTimeEdit->time());
764 }
765 
766 /******************************************************************************
767  * Set all controls to their default values.
768  */
769 void RecurrenceEdit::setDefaults(const TQDateTime& from)
770 {
771  mCurrStartDateTime = from;
772  TQDate fromDate = from.date();
773  mNoEndDateButton->setChecked(true);
774 
775  mSubDailyRule->setFrequency(1);
776  mDailyRule->setFrequency(1);
777  mWeeklyRule->setFrequency(1);
778  mMonthlyRule->setFrequency(1);
779  mYearlyRule->setFrequency(1);
780 
781  setRuleDefaults(fromDate);
782  mMonthlyRule->setType(MonthYearRule::DATE); // date in month
783  mYearlyRule->setType(MonthYearRule::DATE); // date in year
784 
785  mEndDateEdit->setDate(fromDate);
786 
787  mNoEmitTypeChanged = true;
788  int button;
789  switch (Preferences::defaultRecurPeriod())
790  {
791  case AT_LOGIN: button = mAtLoginButtonId; break;
792  case ANNUAL: button = mYearlyButtonId; break;
793  case MONTHLY: button = mMonthlyButtonId; break;
794  case WEEKLY: button = mWeeklyButtonId; break;
795  case DAILY: button = mDailyButtonId; break;
796  case SUBDAILY: button = mSubDailyButtonId; break;
797  case NO_RECUR:
798  default: button = mNoneButtonId; break;
799  }
800  mRuleButtonGroup->setButton(button);
801  mNoEmitTypeChanged = false;
802  rangeTypeClicked();
803  enableExceptionButtons();
804 
805  saveState();
806 }
807 
808 /******************************************************************************
809  * Set the controls for weekly, monthly and yearly rules which have not so far
810  * been shown, to their default values, depending on the recurrence start date.
811  */
812 void RecurrenceEdit::setRuleDefaults(const TQDate& fromDate)
813 {
814  int day = fromDate.day();
815  int dayOfWeek = fromDate.dayOfWeek();
816  int month = fromDate.month();
817  if (!mDailyShown)
818  mDailyRule->setDays(true);
819  if (!mWeeklyShown)
820  mWeeklyRule->setDay(dayOfWeek);
821  if (!mMonthlyShown)
822  mMonthlyRule->setDefaultValues(day, dayOfWeek);
823  if (!mYearlyShown)
824  mYearlyRule->setDefaultValues(day, dayOfWeek, month);
825 }
826 
827 /******************************************************************************
828 * Set the state of all controls to reflect the data in the specified event.
829 * Set 'keepDuration' true to prevent the recurrence count being adjusted to the
830 * remaining number of recurrences.
831 */
832 void RecurrenceEdit::set(const KAEvent& event, bool keepDuration)
833 {
834  setDefaults(event.mainDateTime().dateTime());
835  if (event.repeatAtLogin())
836  {
837  mRuleButtonGroup->setButton(mAtLoginButtonId);
838  mEndDateButton->setChecked(true);
839  return;
840  }
841  mRuleButtonGroup->setButton(mNoneButtonId);
842  KARecurrence* recurrence = event.recurrence();
843  if (!recurrence)
844  return;
845  KARecurrence::Type rtype = recurrence->type();
846  switch (rtype)
847  {
848  case KARecurrence::MINUTELY:
849  mRuleButtonGroup->setButton(mSubDailyButtonId);
850  break;
851 
852  case KARecurrence::DAILY:
853  {
854  mRuleButtonGroup->setButton(mDailyButtonId);
855  TQBitArray rDays = recurrence->days();
856  bool set = false;
857  for (int i = 0; i < 7 && !set; ++i)
858  set = rDays.testBit(i);
859  if (set)
860  mDailyRule->setDays(rDays);
861  else
862  mDailyRule->setDays(true);
863  break;
864  }
865  case KARecurrence::WEEKLY:
866  {
867  mRuleButtonGroup->setButton(mWeeklyButtonId);
868  TQBitArray rDays = recurrence->days();
869  mWeeklyRule->setDays(rDays);
870  break;
871  }
872  case KARecurrence::MONTHLY_POS: // on nth (Tuesday) of the month
873  {
874  TQValueList<RecurrenceRule::WDayPos> posns = recurrence->monthPositions();
875  int i = posns.first().pos();
876  if (!i)
877  {
878  // It's every (Tuesday) of the month. Convert to a weekly recurrence
879  // (but ignoring any non-every xxxDay positions).
880  mRuleButtonGroup->setButton(mWeeklyButtonId);
881  mWeeklyRule->setFrequency(recurrence->frequency());
882  TQBitArray rDays(7);
883  for (TQValueList<RecurrenceRule::WDayPos>::ConstIterator it = posns.begin(); it != posns.end(); ++it)
884  {
885  if (!(*it).pos())
886  rDays.setBit((*it).day() - 1, 1);
887  }
888  mWeeklyRule->setDays(rDays);
889  break;
890  }
891  mRuleButtonGroup->setButton(mMonthlyButtonId);
892  mMonthlyRule->setPosition(i, posns.first().day());
893  break;
894  }
895  case KARecurrence::MONTHLY_DAY: // on nth day of the month
896  {
897  mRuleButtonGroup->setButton(mMonthlyButtonId);
898  TQValueList<int> rmd = recurrence->monthDays();
899  int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
900  mMonthlyRule->setDate(day);
901  break;
902  }
903  case KARecurrence::ANNUAL_DATE: // on the nth day of (months...) in the year
904  case KARecurrence::ANNUAL_POS: // on the nth (Tuesday) of (months...) in the year
905  {
906  if (rtype == KARecurrence::ANNUAL_DATE)
907  {
908  mRuleButtonGroup->setButton(mYearlyButtonId);
909  const TQValueList<int> rmd = recurrence->monthDays();
910  int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
911  mYearlyRule->setDate(day);
912  mYearlyRule->setFeb29Type(recurrence->feb29Type());
913  }
914  else if (rtype == KARecurrence::ANNUAL_POS)
915  {
916  mRuleButtonGroup->setButton(mYearlyButtonId);
917  TQValueList<RecurrenceRule::WDayPos> posns = recurrence->yearPositions();
918  mYearlyRule->setPosition(posns.first().pos(), posns.first().day());
919  }
920  mYearlyRule->setMonths(recurrence->yearMonths());
921  break;
922  }
923  default:
924  return;
925  }
926 
927  mRule->setFrequency(recurrence->frequency());
928 
929  // Get range information
930  TQDateTime endtime = mCurrStartDateTime;
931  int duration = recurrence->duration();
932  if (duration == -1)
933  mNoEndDateButton->setChecked(true);
934  else if (duration)
935  {
936  mRepeatCountButton->setChecked(true);
937  mRepeatCountEntry->setValue(duration);
938  }
939  else
940  {
941  mEndDateButton->setChecked(true);
942  endtime = recurrence->endDateTime();
943  mEndTimeEdit->setValue(endtime.time());
944  }
945  mEndDateEdit->setDate(endtime.date());
946 
947  // Get exception information
948  mExceptionDates = event.recurrence()->exDates();
949  qHeapSort(mExceptionDates);
950  mExceptionDateList->clear();
951  for (DateList::ConstIterator it = mExceptionDates.begin(); it != mExceptionDates.end(); ++it)
952  mExceptionDateList->insertItem(TDEGlobal::locale()->formatDate(*it));
953  enableExceptionButtons();
954 
955  // Get repetition within recurrence
956  mSubRepetition->set(event.repeatInterval(), event.repeatCount());
957 
958  rangeTypeClicked();
959 
960  saveState();
961 }
962 
963 /******************************************************************************
964  * Update the specified KAEvent with the entered recurrence data.
965  * If 'adjustStart' is true, the start date/time will be adjusted if necessary
966  * to be the first date/time which recurs on or after the original start.
967  */
968 void RecurrenceEdit::updateEvent(KAEvent& event, bool adjustStart)
969 {
970  // Get end date and repeat count, common to all types of recurring events
971  TQDate endDate;
972  TQTime endTime;
973  int repeatCount;
974  if (mNoEndDateButton->isChecked())
975  repeatCount = -1;
976  else if (mRepeatCountButton->isChecked())
977  repeatCount = mRepeatCountEntry->value();
978  else
979  {
980  repeatCount = 0;
981  endDate = mEndDateEdit->date();
982  endTime = mEndTimeEdit->time();
983  }
984 
985  // Set up the recurrence according to the type selected
986  TQButton* button = mRuleButtonGroup->selected();
987  event.setRepeatAtLogin(button == mAtLoginButton);
988  int frequency = mRule ? mRule->frequency() : 0;
989  if (button == mSubDailyButton)
990  {
991  TQDateTime endDateTime(endDate, endTime);
992  event.setRecurMinutely(frequency, repeatCount, endDateTime);
993  }
994  else if (button == mDailyButton)
995  {
996  event.setRecurDaily(frequency, mDailyRule->days(), repeatCount, endDate);
997  }
998  else if (button == mWeeklyButton)
999  {
1000  event.setRecurWeekly(frequency, mWeeklyRule->days(), repeatCount, endDate);
1001  }
1002  else if (button == mMonthlyButton)
1003  {
1004  if (mMonthlyRule->type() == MonthlyRule::POS)
1005  {
1006  // It's by position
1007  KAEvent::MonthPos pos;
1008  pos.days.fill(false);
1009  pos.days.setBit(mMonthlyRule->dayOfWeek() - 1);
1010  pos.weeknum = mMonthlyRule->week();
1011  TQValueList<KAEvent::MonthPos> poses;
1012  poses.append(pos);
1013  event.setRecurMonthlyByPos(frequency, poses, repeatCount, endDate);
1014  }
1015  else
1016  {
1017  // It's by day
1018  int daynum = mMonthlyRule->date();
1019  TQValueList<int> daynums;
1020  daynums.append(daynum);
1021  event.setRecurMonthlyByDate(frequency, daynums, repeatCount, endDate);
1022  }
1023  }
1024  else if (button == mYearlyButton)
1025  {
1026  TQValueList<int> months = mYearlyRule->months();
1027  if (mYearlyRule->type() == YearlyRule::POS)
1028  {
1029  // It's by position
1030  KAEvent::MonthPos pos;
1031  pos.days.fill(false);
1032  pos.days.setBit(mYearlyRule->dayOfWeek() - 1);
1033  pos.weeknum = mYearlyRule->week();
1034  TQValueList<KAEvent::MonthPos> poses;
1035  poses.append(pos);
1036  event.setRecurAnnualByPos(frequency, poses, months, repeatCount, endDate);
1037  }
1038  else
1039  {
1040  // It's by date in month
1041  event.setRecurAnnualByDate(frequency, months, mYearlyRule->date(),
1042  mYearlyRule->feb29Type(), repeatCount, endDate);
1043  }
1044  }
1045  else
1046  {
1047  event.setNoRecur();
1048  return;
1049  }
1050  if (!event.recurs())
1051  return; // an error occurred setting up the recurrence
1052  if (adjustStart)
1053  event.setFirstRecurrence();
1054 
1055  // Set up repetition within the recurrence.
1056  // N.B. This requires the main recurrence to be set up first.
1057  int count = mSubRepetition->count();
1058  if (mRuleButtonType < SUBDAILY)
1059  count = 0;
1060  event.setRepetition(mSubRepetition->interval(), count);
1061 
1062  // Set up exceptions
1063  event.recurrence()->setExDates(mExceptionDates);
1064 
1065  event.setUpdated();
1066 }
1067 
1068 /******************************************************************************
1069  * Save the state of all controls.
1070  */
1071 void RecurrenceEdit::saveState()
1072 {
1073  mSavedRuleButton = mRuleButtonGroup->selected();
1074  if (mRule)
1075  mRule->saveState();
1076  mSavedRangeButton = mRangeButtonGroup->selected();
1077  if (mSavedRangeButton == mRepeatCountButton)
1078  mSavedRecurCount = mRepeatCountEntry->value();
1079  else if (mSavedRangeButton == mEndDateButton)
1080  mSavedEndDateTime.set(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked());
1081  mSavedExceptionDates = mExceptionDates;
1082  mSavedRepeatInterval = mSubRepetition->interval();
1083  mSavedRepeatCount = mSubRepetition->count();
1084 }
1085 
1086 /******************************************************************************
1087  * Check whether any of the controls have changed state since initialisation.
1088  */
1089 bool RecurrenceEdit::stateChanged() const
1090 {
1091  if (mSavedRuleButton != mRuleButtonGroup->selected()
1092  || mSavedRangeButton != mRangeButtonGroup->selected()
1093  || (mRule && mRule->stateChanged()))
1094  return true;
1095  if (mSavedRangeButton == mRepeatCountButton
1096  && mSavedRecurCount != mRepeatCountEntry->value())
1097  return true;
1098  if (mSavedRangeButton == mEndDateButton
1099  && mSavedEndDateTime != DateTime(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked()))
1100  return true;
1101  if (mSavedExceptionDates != mExceptionDates
1102  || mSavedRepeatInterval != mSubRepetition->interval()
1103  || mSavedRepeatCount != mSubRepetition->count())
1104  return true;
1105  return false;
1106 }
1107 
1108 
1109 
1110 /*=============================================================================
1111 = Class Rule
1112 = Base class for rule widgets, including recurrence frequency.
1113 =============================================================================*/
1114 
1115 Rule::Rule(const TQString& freqText, const TQString& freqWhatsThis, bool time, bool readOnly, TQWidget* parent, const char* name)
1116  : NoRule(parent, name)
1117 {
1118  mLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint());
1119  TQHBox* freqBox = new TQHBox(this);
1120  mLayout->addWidget(freqBox);
1121  TQHBox* box = new TQHBox(freqBox); // this is to control the TQWhatsThis text display area
1122  box->setSpacing(KDialog::spacingHint());
1123 
1124  TQLabel* label = new TQLabel(i18n("Recur e&very"), box);
1125  label->setFixedSize(label->sizeHint());
1126  if (time)
1127  {
1128  mIntSpinBox = 0;
1129  mSpinBox = mTimeSpinBox = new TimeSpinBox(1, 5999, box);
1130  mTimeSpinBox->setFixedSize(mTimeSpinBox->sizeHint());
1131  mTimeSpinBox->setReadOnly(readOnly);
1132  }
1133  else
1134  {
1135  mTimeSpinBox = 0;
1136  mSpinBox = mIntSpinBox = new SpinBox(1, 999, 1, box);
1137  mIntSpinBox->setFixedSize(mIntSpinBox->sizeHint());
1138  mIntSpinBox->setReadOnly(readOnly);
1139  }
1140  connect(mSpinBox, TQ_SIGNAL(valueChanged(int)), TQ_SIGNAL(frequencyChanged()));
1141  label->setBuddy(mSpinBox);
1142  label = new TQLabel(freqText, box);
1143  label->setFixedSize(label->sizeHint());
1144  box->setFixedSize(sizeHint());
1145  TQWhatsThis::add(box, freqWhatsThis);
1146 
1147  new TQWidget(freqBox); // left adjust the visible widgets
1148  freqBox->setFixedHeight(freqBox->sizeHint().height());
1149  freqBox->setFocusProxy(mSpinBox);
1150 }
1151 
1152 int Rule::frequency() const
1153 {
1154  if (mIntSpinBox)
1155  return mIntSpinBox->value();
1156  if (mTimeSpinBox)
1157  return mTimeSpinBox->value();
1158  return 0;
1159 }
1160 
1161 void Rule::setFrequency(int n)
1162 {
1163  if (mIntSpinBox)
1164  mIntSpinBox->setValue(n);
1165  if (mTimeSpinBox)
1166  mTimeSpinBox->setValue(n);
1167 }
1168 
1169 /******************************************************************************
1170  * Save the state of all controls.
1171  */
1172 void Rule::saveState()
1173 {
1174  mSavedFrequency = frequency();
1175 }
1176 
1177 /******************************************************************************
1178  * Check whether any of the controls have changed state since initialisation.
1179  */
1180 bool Rule::stateChanged() const
1181 {
1182  return (mSavedFrequency != frequency());
1183 }
1184 
1185 
1186 /*=============================================================================
1187 = Class SubDailyRule
1188 = Sub-daily rule widget.
1189 =============================================================================*/
1190 
1191 SubDailyRule::SubDailyRule(bool readOnly, TQWidget* parent, const char* name)
1192  : Rule(i18n("hours:minutes"),
1193  i18n("Enter the number of hours and minutes between repetitions of the alarm"),
1194  true, readOnly, parent, name)
1195 { }
1196 
1197 
1198 /*=============================================================================
1199 = Class DayWeekRule
1200 = Daily/weekly rule widget base class.
1201 =============================================================================*/
1202 
1203 DayWeekRule::DayWeekRule(const TQString& freqText, const TQString& freqWhatsThis, const TQString& daysWhatsThis,
1204  bool readOnly, TQWidget* parent, const char* name)
1205  : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
1206  mSavedDays(7)
1207 {
1208  TQGridLayout* grid = new TQGridLayout(layout(), 1, 4, KDialog::spacingHint());
1209  grid->setRowStretch(0, 1);
1210 
1211  TQLabel* label = new TQLabel(i18n("On: Tuesday", "O&n:"), this);
1212  label->setFixedSize(label->sizeHint());
1213  grid->addWidget(label, 0, 0, TQt::AlignRight | TQt::AlignTop);
1214  grid->addColSpacing(1, KDialog::spacingHint());
1215 
1216  // List the days of the week starting at the user's start day of the week.
1217  // Save the first day of the week, just in case it changes while the dialog is open.
1218  TQWidget* box = new TQWidget(this); // this is to control the TQWhatsThis text display area
1219  TQGridLayout* dgrid = new TQGridLayout(box, 4, 2, 0, KDialog::spacingHint());
1220  const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
1221  for (int i = 0; i < 7; ++i)
1222  {
1223  int day = KAlarm::localeDayInWeek_to_weekDay(i);
1224  mDayBox[i] = new CheckBox(calendar->weekDayName(day), box);
1225  mDayBox[i]->setFixedSize(mDayBox[i]->sizeHint());
1226  mDayBox[i]->setReadOnly(readOnly);
1227  dgrid->addWidget(mDayBox[i], i%4, i/4, TQt::AlignAuto);
1228  }
1229  box->setFixedSize(box->sizeHint());
1230  TQWhatsThis::add(box, daysWhatsThis);
1231  grid->addWidget(box, 0, 2, TQt::AlignAuto);
1232  label->setBuddy(mDayBox[0]);
1233  grid->setColStretch(3, 1);
1234 }
1235 
1236 /******************************************************************************
1237  * Fetch which days of the week have been ticked.
1238  */
1239 TQBitArray DayWeekRule::days() const
1240 {
1241  TQBitArray ds(7);
1242  ds.fill(false);
1243  for (int i = 0; i < 7; ++i)
1244  if (mDayBox[i]->isChecked())
1245  ds.setBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1, 1);
1246  return ds;
1247 }
1248 
1249 /******************************************************************************
1250  * Tick/untick every day of the week.
1251  */
1252 void DayWeekRule::setDays(bool tick)
1253 {
1254  for (int i = 0; i < 7; ++i)
1255  mDayBox[i]->setChecked(tick);
1256 }
1257 
1258 /******************************************************************************
1259  * Tick/untick each day of the week according to the specified bits.
1260  */
1261 void DayWeekRule::setDays(const TQBitArray& days)
1262 {
1263  for (int i = 0; i < 7; ++i)
1264  {
1265  bool x = days.testBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1);
1266  mDayBox[i]->setChecked(x);
1267  }
1268 }
1269 
1270 /******************************************************************************
1271  * Tick the specified day of the week, and untick all other days.
1272  */
1273 void DayWeekRule::setDay(int dayOfWeek)
1274 {
1275  for (int i = 0; i < 7; ++i)
1276  mDayBox[i]->setChecked(false);
1277  if (dayOfWeek > 0 && dayOfWeek <= 7)
1278  mDayBox[KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)]->setChecked(true);
1279 }
1280 
1281 /******************************************************************************
1282  * Validate: check that at least one day is selected.
1283  */
1284 TQWidget* DayWeekRule::validate(TQString& errorMessage)
1285 {
1286  for (int i = 0; i < 7; ++i)
1287  if (mDayBox[i]->isChecked())
1288  return 0;
1289  errorMessage = i18n("No day selected");
1290  return mDayBox[0];
1291 }
1292 
1293 /******************************************************************************
1294  * Save the state of all controls.
1295  */
1296 void DayWeekRule::saveState()
1297 {
1298  Rule::saveState();
1299  mSavedDays = days();
1300 }
1301 
1302 /******************************************************************************
1303  * Check whether any of the controls have changed state since initialisation.
1304  */
1305 bool DayWeekRule::stateChanged() const
1306 {
1307  return (Rule::stateChanged()
1308  || mSavedDays != days());
1309 }
1310 
1311 
1312 /*=============================================================================
1313 = Class DailyRule
1314 = Daily rule widget.
1315 =============================================================================*/
1316 
1317 DailyRule::DailyRule(bool readOnly, TQWidget* parent, const char* name)
1318  : DayWeekRule(i18n("day(s)"),
1319  i18n("Enter the number of days between repetitions of the alarm"),
1320  i18n("Select the days of the week on which the alarm is allowed to occur"),
1321  readOnly, parent, name)
1322 { }
1323 
1324 
1325 /*=============================================================================
1326 = Class WeeklyRule
1327 = Weekly rule widget.
1328 =============================================================================*/
1329 
1330 WeeklyRule::WeeklyRule(bool readOnly, TQWidget* parent, const char* name)
1331  : DayWeekRule(i18n("week(s)"),
1332  i18n("Enter the number of weeks between repetitions of the alarm"),
1333  i18n("Select the days of the week on which to repeat the alarm"),
1334  readOnly, parent, name)
1335 { }
1336 
1337 
1338 /*=============================================================================
1339 = Class MonthYearRule
1340 = Monthly/yearly rule widget base class.
1341 =============================================================================*/
1342 
1343 MonthYearRule::MonthYearRule(const TQString& freqText, const TQString& freqWhatsThis, bool allowEveryWeek,
1344  bool readOnly, TQWidget* parent, const char* name)
1345  : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
1346  mEveryWeek(allowEveryWeek)
1347 {
1348  mButtonGroup = new ButtonGroup(this);
1349  mButtonGroup->hide();
1350 
1351  // Month day selector
1352  TQHBox* box = new TQHBox(this);
1353  box->setSpacing(KDialog::spacingHint());
1354  layout()->addWidget(box);
1355 
1356  mDayButton = new RadioButton(i18n("On day number in the month", "O&n day"), box);
1357  mDayButton->setFixedSize(mDayButton->sizeHint());
1358  mDayButton->setReadOnly(readOnly);
1359  mDayButtonId = mButtonGroup->insert(mDayButton);
1360  TQWhatsThis::add(mDayButton, i18n("Repeat the alarm on the selected day of the month"));
1361 
1362  mDayCombo = new ComboBox(false, box);
1363  mDayCombo->setSizeLimit(11);
1364  for (int i = 0; i < 31; ++i)
1365  mDayCombo->insertItem(TQString::number(i + 1));
1366  mDayCombo->insertItem(i18n("Last day of month", "Last"));
1367  mDayCombo->setFixedSize(mDayCombo->sizeHint());
1368  mDayCombo->setReadOnly(readOnly);
1369  TQWhatsThis::add(mDayCombo, i18n("Select the day of the month on which to repeat the alarm"));
1370  mDayButton->setFocusWidget(mDayCombo);
1371  connect(mDayCombo, TQ_SIGNAL(activated(int)), TQ_SLOT(slotDaySelected(int)));
1372 
1373  box->setStretchFactor(new TQWidget(box), 1); // left adjust the controls
1374  box->setFixedHeight(box->sizeHint().height());
1375 
1376  // Month position selector
1377  box = new TQHBox(this);
1378  box->setSpacing(KDialog::spacingHint());
1379  layout()->addWidget(box);
1380 
1381  mPosButton = new RadioButton(i18n("On the 1st Tuesday", "On t&he"), box);
1382  mPosButton->setFixedSize(mPosButton->sizeHint());
1383  mPosButton->setReadOnly(readOnly);
1384  mPosButtonId = mButtonGroup->insert(mPosButton);
1385  TQWhatsThis::add(mPosButton,
1386  i18n("Repeat the alarm on one day of the week, in the selected week of the month"));
1387 
1388  mWeekCombo = new ComboBox(false, box);
1389  mWeekCombo->insertItem(i18n("1st"));
1390  mWeekCombo->insertItem(i18n("2nd"));
1391  mWeekCombo->insertItem(i18n("3rd"));
1392  mWeekCombo->insertItem(i18n("4th"));
1393  mWeekCombo->insertItem(i18n("5th"));
1394  mWeekCombo->insertItem(i18n("Last Monday in March", "Last"));
1395  mWeekCombo->insertItem(i18n("2nd Last"));
1396  mWeekCombo->insertItem(i18n("3rd Last"));
1397  mWeekCombo->insertItem(i18n("4th Last"));
1398  mWeekCombo->insertItem(i18n("5th Last"));
1399  if (mEveryWeek)
1400  {
1401  mWeekCombo->insertItem(i18n("Every (Monday...) in month", "Every"));
1402  mWeekCombo->setSizeLimit(11);
1403  }
1404  TQWhatsThis::add(mWeekCombo, i18n("Select the week of the month in which to repeat the alarm"));
1405  mWeekCombo->setFixedSize(mWeekCombo->sizeHint());
1406  mWeekCombo->setReadOnly(readOnly);
1407  mPosButton->setFocusWidget(mWeekCombo);
1408 
1409  mDayOfWeekCombo = new ComboBox(false, box);
1410  const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
1411  for (int i = 0; i < 7; ++i)
1412  {
1413  int day = KAlarm::localeDayInWeek_to_weekDay(i);
1414  mDayOfWeekCombo->insertItem(calendar->weekDayName(day));
1415  }
1416  mDayOfWeekCombo->setReadOnly(readOnly);
1417  TQWhatsThis::add(mDayOfWeekCombo, i18n("Select the day of the week on which to repeat the alarm"));
1418 
1419  box->setStretchFactor(new TQWidget(box), 1); // left adjust the controls
1420  box->setFixedHeight(box->sizeHint().height());
1421  connect(mButtonGroup, TQ_SIGNAL(buttonSet(int)), TQ_SLOT(clicked(int)));
1422 }
1423 
1424 MonthYearRule::DayPosType MonthYearRule::type() const
1425 {
1426  return (mButtonGroup->selectedId() == mDayButtonId) ? DATE : POS;
1427 }
1428 
1429 void MonthYearRule::setType(MonthYearRule::DayPosType type)
1430 {
1431  mButtonGroup->setButton(type == DATE ? mDayButtonId : mPosButtonId);
1432 }
1433 
1434 void MonthYearRule::setDefaultValues(int dayOfMonth, int dayOfWeek)
1435 {
1436  --dayOfMonth;
1437  mDayCombo->setCurrentItem(dayOfMonth);
1438  mWeekCombo->setCurrentItem(dayOfMonth / 7);
1439  mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
1440 }
1441 
1442 int MonthYearRule::date() const
1443 {
1444  int daynum = mDayCombo->currentItem() + 1;
1445  return (daynum <= 31) ? daynum : 31 - daynum;
1446 }
1447 
1448 int MonthYearRule::week() const
1449 {
1450  int weeknum = mWeekCombo->currentItem() + 1;
1451  return (weeknum <= 5) ? weeknum : (weeknum == 11) ? 0 : 5 - weeknum;
1452 }
1453 
1454 int MonthYearRule::dayOfWeek() const
1455 {
1456  return KAlarm::localeDayInWeek_to_weekDay(mDayOfWeekCombo->currentItem());
1457 }
1458 
1459 void MonthYearRule::setDate(int dayOfMonth)
1460 {
1461  mButtonGroup->setButton(mDayButtonId);
1462  mDayCombo->setCurrentItem(dayOfMonth > 0 ? dayOfMonth - 1 : dayOfMonth < 0 ? 30 - dayOfMonth : 0); // day 0 shouldn't ever occur
1463 }
1464 
1465 void MonthYearRule::setPosition(int week, int dayOfWeek)
1466 {
1467  mButtonGroup->setButton(mPosButtonId);
1468  mWeekCombo->setCurrentItem((week > 0) ? week - 1 : (week < 0) ? 4 - week : mEveryWeek ? 10 : 0);
1469  mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
1470 }
1471 
1472 void MonthYearRule::enableSelection(DayPosType type)
1473 {
1474  bool date = (type == DATE);
1475  mDayCombo->setEnabled(date);
1476  mWeekCombo->setEnabled(!date);
1477  mDayOfWeekCombo->setEnabled(!date);
1478 }
1479 
1480 void MonthYearRule::clicked(int id)
1481 {
1482  enableSelection(id == mDayButtonId ? DATE : POS);
1483 }
1484 
1485 void MonthYearRule::slotDaySelected(int index)
1486 {
1487  daySelected(index <= 30 ? index + 1 : 30 - index);
1488 }
1489 
1490 /******************************************************************************
1491  * Save the state of all controls.
1492  */
1493 void MonthYearRule::saveState()
1494 {
1495  Rule::saveState();
1496  mSavedType = type();
1497  if (mSavedType == DATE)
1498  mSavedDay = date();
1499  else
1500  {
1501  mSavedWeek = week();
1502  mSavedWeekDay = dayOfWeek();
1503  }
1504 }
1505 
1506 /******************************************************************************
1507  * Check whether any of the controls have changed state since initialisation.
1508  */
1509 bool MonthYearRule::stateChanged() const
1510 {
1511  if (Rule::stateChanged()
1512  || mSavedType != type())
1513  return true;
1514  if (mSavedType == DATE)
1515  {
1516  if (mSavedDay != date())
1517  return true;
1518  }
1519  else
1520  {
1521  if (mSavedWeek != week()
1522  || mSavedWeekDay != dayOfWeek())
1523  return true;
1524  }
1525  return false;
1526 }
1527 
1528 
1529 /*=============================================================================
1530 = Class MonthlyRule
1531 = Monthly rule widget.
1532 =============================================================================*/
1533 
1534 MonthlyRule::MonthlyRule(bool readOnly, TQWidget* parent, const char* name)
1535  : MonthYearRule(i18n("month(s)"),
1536  i18n("Enter the number of months between repetitions of the alarm"),
1537  false, readOnly, parent, name)
1538 { }
1539 
1540 
1541 /*=============================================================================
1542 = Class YearlyRule
1543 = Yearly rule widget.
1544 =============================================================================*/
1545 
1546 YearlyRule::YearlyRule(bool readOnly, TQWidget* parent, const char* name)
1547  : MonthYearRule(i18n("year(s)"),
1548  i18n("Enter the number of years between repetitions of the alarm"),
1549  true, readOnly, parent, name)
1550 {
1551  // Set up the month selection widgets
1552  TQBoxLayout* hlayout = new TQHBoxLayout(layout(), KDialog::spacingHint());
1553  TQLabel* label = new TQLabel(i18n("List of months to select", "Months:"), this);
1554  label->setFixedSize(label->sizeHint());
1555  hlayout->addWidget(label, 0, TQt::AlignAuto | TQt::AlignTop);
1556 
1557  // List the months of the year.
1558  TQWidget* w = new TQWidget(this); // this is to control the TQWhatsThis text display area
1559  hlayout->addWidget(w, 1, TQt::AlignAuto);
1560  TQGridLayout* grid = new TQGridLayout(w, 4, 3, 0, KDialog::spacingHint());
1561  const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
1562  int year = TQDate::currentDate().year();
1563  for (int i = 0; i < 12; ++i)
1564  {
1565  mMonthBox[i] = new CheckBox(calendar->monthName(i + 1, year, true), w);
1566  mMonthBox[i]->setFixedSize(mMonthBox[i]->sizeHint());
1567  mMonthBox[i]->setReadOnly(readOnly);
1568  grid->addWidget(mMonthBox[i], i%3, i/3, TQt::AlignAuto);
1569  }
1570  connect(mMonthBox[1], TQ_SIGNAL(toggled(bool)), TQ_SLOT(enableFeb29()));
1571  w->setFixedHeight(w->sizeHint().height());
1572  TQWhatsThis::add(w, i18n("Select the months of the year in which to repeat the alarm"));
1573 
1574  // February 29th handling option
1575  TQHBox* f29box = new TQHBox(this);
1576  layout()->addWidget(f29box);
1577  TQHBox* box = new TQHBox(f29box); // this is to control the TQWhatsThis text display area
1578  box->setSpacing(KDialog::spacingHint());
1579  mFeb29Label = new TQLabel(i18n("February 2&9th alarm in non-leap years:"), box);
1580  mFeb29Label->setFixedSize(mFeb29Label->sizeHint());
1581  mFeb29Combo = new ComboBox(false, box);
1582  mFeb29Combo->insertItem(i18n("No date", "None"));
1583  mFeb29Combo->insertItem(i18n("1st March (short form)", "1 Mar"));
1584  mFeb29Combo->insertItem(i18n("28th February (short form)", "28 Feb"));
1585  mFeb29Combo->setFixedSize(mFeb29Combo->sizeHint());
1586  mFeb29Combo->setReadOnly(readOnly);
1587  mFeb29Label->setBuddy(mFeb29Combo);
1588  box->setFixedSize(box->sizeHint());
1589  TQWhatsThis::add(box,
1590  i18n("Select which date, if any, the February 29th alarm should trigger in non-leap years"));
1591  new TQWidget(f29box); // left adjust the visible widgets
1592  f29box->setFixedHeight(f29box->sizeHint().height());
1593 }
1594 
1595 void YearlyRule::setDefaultValues(int dayOfMonth, int dayOfWeek, int month)
1596 {
1597  MonthYearRule::setDefaultValues(dayOfMonth, dayOfWeek);
1598  --month;
1599  for (int i = 0; i < 12; ++i)
1600  mMonthBox[i]->setChecked(i == month);
1601  setFeb29Type(Preferences::defaultFeb29Type());
1602  daySelected(dayOfMonth); // enable/disable month checkboxes as appropriate
1603 }
1604 
1605 /******************************************************************************
1606  * Fetch which months have been checked (1 - 12).
1607  * Reply = true if February has been checked.
1608  */
1609 TQValueList<int> YearlyRule::months() const
1610 {
1611  TQValueList<int> mnths;
1612  for (int i = 0; i < 12; ++i)
1613  if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled())
1614  mnths.append(i + 1);
1615  return mnths;
1616 }
1617 
1618 /******************************************************************************
1619  * Check/uncheck each month of the year according to the specified list.
1620  */
1621 void YearlyRule::setMonths(const TQValueList<int>& mnths)
1622 {
1623  bool checked[12];
1624  for (int i = 0; i < 12; ++i)
1625  checked[i] = false;
1626  for (TQValueListConstIterator<int> it = mnths.begin(); it != mnths.end(); ++it)
1627  checked[(*it) - 1] = true;
1628  for (int i = 0; i < 12; ++i)
1629  mMonthBox[i]->setChecked(checked[i]);
1630  enableFeb29();
1631 }
1632 
1633 /******************************************************************************
1634  * Return the date for February 29th alarms in non-leap years.
1635  */
1636 KARecurrence::Feb29Type YearlyRule::feb29Type() const
1637 {
1638  if (mFeb29Combo->isEnabled())
1639  {
1640  switch (mFeb29Combo->currentItem())
1641  {
1642  case 1: return KARecurrence::FEB29_MAR1;
1643  case 2: return KARecurrence::FEB29_FEB28;
1644  default: break;
1645  }
1646  }
1647  return KARecurrence::FEB29_FEB29;
1648 }
1649 
1650 /******************************************************************************
1651  * Set the date for February 29th alarms to trigger in non-leap years.
1652  */
1653 void YearlyRule::setFeb29Type(KARecurrence::Feb29Type type)
1654 {
1655  int index;
1656  switch (type)
1657  {
1658  default:
1659  case KARecurrence::FEB29_FEB29: index = 0; break;
1660  case KARecurrence::FEB29_MAR1: index = 1; break;
1661  case KARecurrence::FEB29_FEB28: index = 2; break;
1662  }
1663  mFeb29Combo->setCurrentItem(index);
1664 }
1665 
1666 /******************************************************************************
1667  * Validate: check that at least one month is selected.
1668  */
1669 TQWidget* YearlyRule::validate(TQString& errorMessage)
1670 {
1671  for (int i = 0; i < 12; ++i)
1672  if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled())
1673  return 0;
1674  errorMessage = i18n("No month selected");
1675  return mMonthBox[0];
1676 }
1677 
1678 /******************************************************************************
1679  * Called when a yearly recurrence type radio button is clicked,
1680  * to enable/disable month checkboxes as appropriate for the date selected.
1681  */
1682 void YearlyRule::clicked(int id)
1683 {
1684  MonthYearRule::clicked(id);
1685  daySelected(buttonType(id) == DATE ? date() : 1);
1686 }
1687 
1688 /******************************************************************************
1689  * Called when a day of the month is selected in a yearly recurrence, to
1690  * disable months for which the day is out of range.
1691  */
1692 void YearlyRule::daySelected(int day)
1693 {
1694  mMonthBox[1]->setEnabled(day <= 29); // February
1695  bool enable = (day != 31);
1696  mMonthBox[3]->setEnabled(enable); // April
1697  mMonthBox[5]->setEnabled(enable); // June
1698  mMonthBox[8]->setEnabled(enable); // September
1699  mMonthBox[10]->setEnabled(enable); // November
1700  enableFeb29();
1701 }
1702 
1703 /******************************************************************************
1704  * Enable/disable the February 29th combo box depending on whether February
1705  * 29th is selected.
1706  */
1707 void YearlyRule::enableFeb29()
1708 {
1709  bool enable = (type() == DATE && date() == 29 && mMonthBox[1]->isChecked() && mMonthBox[1]->isEnabled());
1710  mFeb29Label->setEnabled(enable);
1711  mFeb29Combo->setEnabled(enable);
1712 }
1713 
1714 /******************************************************************************
1715  * Save the state of all controls.
1716  */
1717 void YearlyRule::saveState()
1718 {
1719  MonthYearRule::saveState();
1720  mSavedMonths = months();
1721  mSavedFeb29Type = feb29Type();
1722 }
1723 
1724 /******************************************************************************
1725  * Check whether any of the controls have changed state since initialisation.
1726  */
1727 bool YearlyRule::stateChanged() const
1728 {
1729  return (MonthYearRule::stateChanged()
1730  || mSavedMonths != months()
1731  || mSavedFeb29Type != feb29Type());
1732 }
represents calendar alarms and events
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
miscellaneous functions
the KAlarm application object