• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kalarm

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

KDE's Doxygen guidelines are available online.

kalarm

Skip menu "kalarm"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal