2 * recurrenceedit.cpp - widget to edit the event's recurrence definition
4 * Copyright © 2002-2016 by David Jarvie <djarvie@kde.org>
6 * Based originally on KOrganizer module koeditorrecurrence.cpp,
7 * Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
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.
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.
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.
25 #include "recurrenceedit.h"
26 #include "recurrenceedit_p.h"
28 #include "alarmtimewidget.h"
31 #include "kalarmapp.h"
33 #include "preferences.h"
34 #include "radiobutton.h"
35 #include "repetitionbutton.h"
38 #include "timespinbox.h"
39 #include "buttongroup.h"
41 #include <kalarmcal/kaevent.h>
42 #include <kalarmcal/karecurrence.h>
44 #include <KCalCore/Event>
45 using namespace KCalCore
;
47 #include <KLocalizedString>
48 #include <kcalendarsystem.h>
49 #include <kmessagebox.h>
50 #include <kdatecombobox.h>
52 #include <QHBoxLayout>
53 #include <QPushButton>
55 #include <QStackedWidget>
56 #include <QListWidget>
58 #include <QGridLayout>
59 #include <QHBoxLayout>
60 #include <QVBoxLayout>
61 #include <QtAlgorithms>
62 #include "kalarm_debug.h"
65 class ListWidget
: public QListWidget
68 explicit ListWidget(QWidget
* parent
) : QListWidget(parent
) {}
69 QSize
sizeHint() const Q_DECL_OVERRIDE
{ return minimumSizeHint(); }
72 // Collect these widget labels together to ensure consistent wording and
73 // translations across different modules.
74 QString
RecurrenceEdit::i18n_combo_NoRecur() { return i18nc("@item:inlistbox Recurrence type", "No Recurrence"); }
75 QString
RecurrenceEdit::i18n_combo_AtLogin() { return i18nc("@item:inlistbox Recurrence type", "At Login"); }
76 QString
RecurrenceEdit::i18n_combo_HourlyMinutely() { return i18nc("@item:inlistbox Recurrence type", "Hourly/Minutely"); }
77 QString
RecurrenceEdit::i18n_combo_Daily() { return i18nc("@item:inlistbox Recurrence type", "Daily"); }
78 QString
RecurrenceEdit::i18n_combo_Weekly() { return i18nc("@item:inlistbox Recurrence type", "Weekly"); }
79 QString
RecurrenceEdit::i18n_combo_Monthly() { return i18nc("@item:inlistbox Recurrence type", "Monthly"); }
80 QString
RecurrenceEdit::i18n_combo_Yearly() { return i18nc("@item:inlistbox Recurrence type", "Yearly"); }
83 RecurrenceEdit::RecurrenceEdit(bool readOnly
, QWidget
* parent
)
86 mRuleButtonType(INVALID_RECUR
),
91 mNoEmitTypeChanged(true),
95 QVBoxLayout
* topLayout
= new QVBoxLayout(this);
96 topLayout
->setMargin(0);
97 topLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
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.
106 QGroupBox
* recurGroup
= new QGroupBox(i18nc("@title:group", "Recurrence Rule"), this);
107 topLayout
->addWidget(recurGroup
);
108 QHBoxLayout
* hlayout
= new QHBoxLayout(recurGroup
);
109 hlayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
110 hlayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultChildMargin
)); // use margin spacing due to vertical divider line
112 // Recurrence period radio buttons
113 QVBoxLayout
* vlayout
= new QVBoxLayout();
114 vlayout
->setSpacing(0);
115 vlayout
->setMargin(0);
116 hlayout
->addLayout(vlayout
);
117 mRuleButtonGroup
= new ButtonGroup(recurGroup
);
118 connect(mRuleButtonGroup
, &ButtonGroup::buttonSet
, this, &RecurrenceEdit::periodClicked
);
119 connect(mRuleButtonGroup
, &ButtonGroup::buttonSet
, this, &RecurrenceEdit::contentsChanged
);
121 mNoneButton
= new RadioButton(i18n_combo_NoRecur(), recurGroup
);
122 mNoneButton
->setFixedSize(mNoneButton
->sizeHint());
123 mNoneButton
->setReadOnly(mReadOnly
);
124 mNoneButton
->setWhatsThis(i18nc("@info:whatsthis", "Do not repeat the alarm"));
125 mRuleButtonGroup
->addButton(mNoneButton
);
126 vlayout
->addWidget(mNoneButton
);
128 mAtLoginButton
= new RadioButton(i18n_combo_AtLogin(), recurGroup
);
129 mAtLoginButton
->setFixedSize(mAtLoginButton
->sizeHint());
130 mAtLoginButton
->setReadOnly(mReadOnly
);
131 mAtLoginButton
->setWhatsThis(xi18nc("@info:whatsthis",
132 "<para>Trigger the alarm at the specified date/time and at every login until then.</para>"
133 "<para>Note that it will also be triggered any time <application>KAlarm</application> is restarted.</para>"));
134 mRuleButtonGroup
->addButton(mAtLoginButton
);
135 vlayout
->addWidget(mAtLoginButton
);
137 mSubDailyButton
= new RadioButton(i18n_combo_HourlyMinutely(), recurGroup
);
138 mSubDailyButton
->setFixedSize(mSubDailyButton
->sizeHint());
139 mSubDailyButton
->setReadOnly(mReadOnly
);
140 mSubDailyButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at hourly/minutely intervals"));
141 mRuleButtonGroup
->addButton(mSubDailyButton
);
142 vlayout
->addWidget(mSubDailyButton
);
144 mDailyButton
= new RadioButton(i18n_combo_Daily(), recurGroup
);
145 mDailyButton
->setFixedSize(mDailyButton
->sizeHint());
146 mDailyButton
->setReadOnly(mReadOnly
);
147 mDailyButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at daily intervals"));
148 mRuleButtonGroup
->addButton(mDailyButton
);
149 vlayout
->addWidget(mDailyButton
);
151 mWeeklyButton
= new RadioButton(i18n_combo_Weekly(), recurGroup
);
152 mWeeklyButton
->setFixedSize(mWeeklyButton
->sizeHint());
153 mWeeklyButton
->setReadOnly(mReadOnly
);
154 mWeeklyButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at weekly intervals"));
155 mRuleButtonGroup
->addButton(mWeeklyButton
);
156 vlayout
->addWidget(mWeeklyButton
);
158 mMonthlyButton
= new RadioButton(i18n_combo_Monthly(), recurGroup
);
159 mMonthlyButton
->setFixedSize(mMonthlyButton
->sizeHint());
160 mMonthlyButton
->setReadOnly(mReadOnly
);
161 mMonthlyButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at monthly intervals"));
162 mRuleButtonGroup
->addButton(mMonthlyButton
);
163 vlayout
->addWidget(mMonthlyButton
);
165 mYearlyButton
= new RadioButton(i18n_combo_Yearly(), recurGroup
);
166 mYearlyButton
->setFixedSize(mYearlyButton
->sizeHint());
167 mYearlyButton
->setReadOnly(mReadOnly
);
168 mYearlyButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at annual intervals"));
169 mRuleButtonGroup
->addButton(mYearlyButton
);
170 vlayout
->addWidget(mYearlyButton
);
171 vlayout
->addStretch(); // top-adjust the interval radio buttons
173 // Sub-repetition button
174 mSubRepetition
= new RepetitionButton(i18nc("@action:button", "Sub-Repetition"), true, recurGroup
);
175 mSubRepetition
->setFixedSize(mSubRepetition
->sizeHint());
176 mSubRepetition
->setReadOnly(mReadOnly
);
177 mSubRepetition
->setWhatsThis(i18nc("@info:whatsthis",
178 "Set up a repetition within the recurrence, to trigger the alarm multiple times each time the recurrence is due."));
179 connect(mSubRepetition
, &RepetitionButton::needsInitialisation
, this, &RecurrenceEdit::repeatNeedsInitialisation
);
180 connect(mSubRepetition
, &RepetitionButton::changed
, this, &RecurrenceEdit::frequencyChanged
);
181 connect(mSubRepetition
, &RepetitionButton::changed
, this, &RecurrenceEdit::contentsChanged
);
182 vlayout
->addSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
183 vlayout
->addWidget(mSubRepetition
);
185 // Vertical divider line
186 vlayout
= new QVBoxLayout();
187 vlayout
->setMargin(0);
188 hlayout
->addLayout(vlayout
);
189 QFrame
* divider
= new QFrame(recurGroup
);
190 divider
->setFrameStyle(QFrame::VLine
| QFrame::Sunken
);
191 vlayout
->addWidget(divider
, 1);
193 // Rule definition stack
194 mRuleStack
= new QStackedWidget(recurGroup
);
195 hlayout
->addWidget(mRuleStack
);
196 hlayout
->addStretch(1);
197 mNoRule
= new NoRule(mRuleStack
);
198 mSubDailyRule
= new SubDailyRule(mReadOnly
, mRuleStack
);
199 mDailyRule
= new DailyRule(mReadOnly
, mRuleStack
);
200 mWeeklyRule
= new WeeklyRule(mReadOnly
, mRuleStack
);
201 mMonthlyRule
= new MonthlyRule(mReadOnly
, mRuleStack
);
202 mYearlyRule
= new YearlyRule(mReadOnly
, mRuleStack
);
204 connect(mSubDailyRule
, &SubDailyRule::frequencyChanged
, this, &RecurrenceEdit::frequencyChanged
);
205 connect(mDailyRule
, &DailyRule::frequencyChanged
, this, &RecurrenceEdit::frequencyChanged
);
206 connect(mWeeklyRule
, &WeeklyRule::frequencyChanged
, this, &RecurrenceEdit::frequencyChanged
);
207 connect(mMonthlyRule
, &MonthlyRule::frequencyChanged
, this, &RecurrenceEdit::frequencyChanged
);
208 connect(mYearlyRule
, &YearlyRule::frequencyChanged
, this, &RecurrenceEdit::frequencyChanged
);
209 connect(mSubDailyRule
, &SubDailyRule::changed
, this, &RecurrenceEdit::contentsChanged
);
210 connect(mDailyRule
, &DailyRule::changed
, this, &RecurrenceEdit::contentsChanged
);
211 connect(mWeeklyRule
, &WeeklyRule::changed
, this, &RecurrenceEdit::contentsChanged
);
212 connect(mMonthlyRule
, &MonthlyRule::changed
, this, &RecurrenceEdit::contentsChanged
);
213 connect(mYearlyRule
, &YearlyRule::changed
, this, &RecurrenceEdit::contentsChanged
);
215 mRuleStack
->addWidget(mNoRule
);
216 mRuleStack
->addWidget(mSubDailyRule
);
217 mRuleStack
->addWidget(mDailyRule
);
218 mRuleStack
->addWidget(mWeeklyRule
);
219 mRuleStack
->addWidget(mMonthlyRule
);
220 mRuleStack
->addWidget(mYearlyRule
);
221 hlayout
->addSpacing(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
223 // Create the recurrence range group which contains the controls
224 // which specify how long the recurrence is to last.
226 mRangeButtonBox
= new QGroupBox(i18nc("@title:group", "Recurrence End"), this);
227 topLayout
->addWidget(mRangeButtonBox
);
228 mRangeButtonGroup
= new ButtonGroup(mRangeButtonBox
);
229 connect(mRangeButtonGroup
, &ButtonGroup::buttonSet
, this, &RecurrenceEdit::rangeTypeClicked
);
230 connect(mRangeButtonGroup
, &ButtonGroup::buttonSet
, this, &RecurrenceEdit::contentsChanged
);
232 vlayout
= new QVBoxLayout(mRangeButtonBox
);
233 vlayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
234 vlayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
235 mNoEndDateButton
= new RadioButton(i18nc("@option:radio", "No end"), mRangeButtonBox
);
236 mNoEndDateButton
->setFixedSize(mNoEndDateButton
->sizeHint());
237 mNoEndDateButton
->setReadOnly(mReadOnly
);
238 mNoEndDateButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm indefinitely"));
239 mRangeButtonGroup
->addButton(mNoEndDateButton
);
240 vlayout
->addWidget(mNoEndDateButton
, 1, Qt::AlignLeft
);
241 QSize size
= mNoEndDateButton
->size();
243 hlayout
= new QHBoxLayout();
244 hlayout
->setMargin(0);
245 vlayout
->addLayout(hlayout
);
246 mRepeatCountButton
= new RadioButton(i18nc("@option:radio", "End after:"), mRangeButtonBox
);
247 mRepeatCountButton
->setReadOnly(mReadOnly
);
248 mRepeatCountButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm for the number of times specified"));
249 mRangeButtonGroup
->addButton(mRepeatCountButton
);
250 mRepeatCountEntry
= new SpinBox(1, 9999, mRangeButtonBox
);
251 mRepeatCountEntry
->setFixedSize(mRepeatCountEntry
->sizeHint());
252 mRepeatCountEntry
->setSingleShiftStep(10);
253 mRepeatCountEntry
->setSelectOnStep(false);
254 mRepeatCountEntry
->setReadOnly(mReadOnly
);
255 mRepeatCountEntry
->setWhatsThis(i18nc("@info:whatsthis", "Enter the total number of times to trigger the alarm"));
256 connect(mRepeatCountEntry
, static_cast<void (SpinBox::*)(int)>(&SpinBox::valueChanged
), this, &RecurrenceEdit::repeatCountChanged
);
257 connect(mRepeatCountEntry
, static_cast<void (SpinBox::*)(int)>(&SpinBox::valueChanged
), this, &RecurrenceEdit::contentsChanged
);
258 mRepeatCountButton
->setFocusWidget(mRepeatCountEntry
);
259 mRepeatCountLabel
= new QLabel(i18nc("@label", "occurrence(s)"), mRangeButtonBox
);
260 mRepeatCountLabel
->setFixedSize(mRepeatCountLabel
->sizeHint());
261 hlayout
->addWidget(mRepeatCountButton
);
262 hlayout
->addSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
263 hlayout
->addWidget(mRepeatCountEntry
);
264 hlayout
->addWidget(mRepeatCountLabel
);
265 hlayout
->addStretch();
266 size
= size
.expandedTo(mRepeatCountButton
->sizeHint());
268 hlayout
= new QHBoxLayout();
269 hlayout
->setMargin(0);
270 vlayout
->addLayout(hlayout
);
271 mEndDateButton
= new RadioButton(i18nc("@option:radio", "End by:"), mRangeButtonBox
);
272 mEndDateButton
->setReadOnly(mReadOnly
);
273 mEndDateButton
->setWhatsThis(
274 xi18nc("@info:whatsthis", "<para>Repeat the alarm until the date/time specified.</para>"
275 "<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>"));
276 mRangeButtonGroup
->addButton(mEndDateButton
);
277 mEndDateEdit
= new KDateComboBox(mRangeButtonBox
);
278 mEndDateEdit
->setOptions(mReadOnly
? KDateComboBox::Options(0) : KDateComboBox::EditDate
| KDateComboBox::SelectDate
| KDateComboBox::DatePicker
);
279 static const QString tzText
= i18nc("@info", "This uses the same time zone as the start time.");
280 mEndDateEdit
->setWhatsThis(xi18nc("@info:whatsthis",
281 "<para>Enter the last date to repeat the alarm.</para><para>%1</para>", tzText
));
282 connect(mEndDateEdit
, &KDateComboBox::dateEdited
, this, &RecurrenceEdit::contentsChanged
);
283 mEndDateButton
->setFocusWidget(mEndDateEdit
);
284 mEndTimeEdit
= new TimeEdit(mRangeButtonBox
);
285 mEndTimeEdit
->setFixedSize(mEndTimeEdit
->sizeHint());
286 mEndTimeEdit
->setReadOnly(mReadOnly
);
287 mEndTimeEdit
->setWhatsThis(xi18nc("@info:whatsthis",
288 "<para>Enter the last time to repeat the alarm.</para><para>%1</para><para>%2</para>", tzText
, TimeSpinBox::shiftWhatsThis()));
289 connect(mEndTimeEdit
, &TimeEdit::valueChanged
, this, &RecurrenceEdit::contentsChanged
);
290 mEndAnyTimeCheckBox
= new CheckBox(i18nc("@option:check", "Any time"), mRangeButtonBox
);
291 mEndAnyTimeCheckBox
->setFixedSize(mEndAnyTimeCheckBox
->sizeHint());
292 mEndAnyTimeCheckBox
->setReadOnly(mReadOnly
);
293 mEndAnyTimeCheckBox
->setWhatsThis(i18nc("@info:whatsthis", "Stop repeating the alarm after your first login on or after the specified end date"));
294 connect(mEndAnyTimeCheckBox
, &CheckBox::toggled
, this, &RecurrenceEdit::slotAnyTimeToggled
);
295 connect(mEndAnyTimeCheckBox
, &CheckBox::toggled
, this, &RecurrenceEdit::contentsChanged
);
296 hlayout
->addWidget(mEndDateButton
);
297 hlayout
->addSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
298 hlayout
->addWidget(mEndDateEdit
);
299 hlayout
->addWidget(mEndTimeEdit
);
300 hlayout
->addWidget(mEndAnyTimeCheckBox
);
301 hlayout
->addStretch();
302 size
= size
.expandedTo(mEndDateButton
->sizeHint());
304 // Line up the widgets to the right of the radio buttons
305 mRepeatCountButton
->setFixedSize(size
);
306 mEndDateButton
->setFixedSize(size
);
308 // Create the exceptions group which specifies dates to be excluded
309 // from the recurrence.
311 mExceptionGroup
= new QGroupBox(i18nc("@title:group", "Exceptions"), this);
312 topLayout
->addWidget(mExceptionGroup
);
313 topLayout
->setStretchFactor(mExceptionGroup
, 2);
314 hlayout
= new QHBoxLayout(mExceptionGroup
);
315 hlayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
316 hlayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
317 vlayout
= new QVBoxLayout();
318 vlayout
->setMargin(0);
319 hlayout
->addLayout(vlayout
);
321 mExceptionDateList
= new ListWidget(mExceptionGroup
);
322 mExceptionDateList
->setWhatsThis(i18nc("@info:whatsthis", "The list of exceptions, i.e. dates/times excluded from the recurrence"));
323 connect(mExceptionDateList
, &QListWidget::currentRowChanged
, this, &RecurrenceEdit::enableExceptionButtons
);
324 vlayout
->addWidget(mExceptionDateList
);
328 mExceptionDateEdit
= Q_NULLPTR
;
329 mChangeExceptionButton
= Q_NULLPTR
;
330 mDeleteExceptionButton
= Q_NULLPTR
;
334 vlayout
= new QVBoxLayout();
335 vlayout
->setMargin(0);
336 hlayout
->addLayout(vlayout
);
337 mExceptionDateEdit
= new KDateComboBox(mExceptionGroup
);
338 mExceptionDateEdit
->setOptions(mReadOnly
? KDateComboBox::Options(0) : KDateComboBox::EditDate
| KDateComboBox::SelectDate
| KDateComboBox::DatePicker
);
339 mExceptionDateEdit
->setDate(KDateTime::currentLocalDate());
340 mExceptionDateEdit
->setWhatsThis(i18nc("@info:whatsthis",
341 "Enter a date to insert in the exceptions list. "
342 "Use in conjunction with the Add or Change button below."));
343 vlayout
->addWidget(mExceptionDateEdit
, 0, Qt::AlignLeft
);
345 hlayout
= new QHBoxLayout();
346 hlayout
->setMargin(0);
347 vlayout
->addLayout(hlayout
);
348 QPushButton
* button
= new QPushButton(i18nc("@action:button", "Add"), mExceptionGroup
);
349 button
->setWhatsThis(i18nc("@info:whatsthis", "Add the date entered above to the exceptions list"));
350 connect(button
, &QPushButton::clicked
, this, &RecurrenceEdit::addException
);
351 hlayout
->addWidget(button
);
353 mChangeExceptionButton
= new QPushButton(i18nc("@action:button", "Change"), mExceptionGroup
);
354 mChangeExceptionButton
->setWhatsThis(i18nc("@info:whatsthis",
355 "Replace the currently highlighted item in the exceptions list with the date entered above"));
356 connect(mChangeExceptionButton
, &QPushButton::clicked
, this, &RecurrenceEdit::changeException
);
357 hlayout
->addWidget(mChangeExceptionButton
);
359 mDeleteExceptionButton
= new QPushButton(i18nc("@action:button", "Delete"), mExceptionGroup
);
360 mDeleteExceptionButton
->setWhatsThis(i18nc("@info:whatsthis", "Remove the currently highlighted item from the exceptions list"));
361 connect(mDeleteExceptionButton
, &QPushButton::clicked
, this, &RecurrenceEdit::deleteException
);
362 hlayout
->addWidget(mDeleteExceptionButton
);
365 vlayout
->addStretch();
367 mExcludeHolidays
= new CheckBox(i18nc("@option:check", "Exclude holidays"), mExceptionGroup
);
368 mExcludeHolidays
->setReadOnly(mReadOnly
);
369 mExcludeHolidays
->setWhatsThis(xi18nc("@info:whatsthis",
370 "<para>Do not trigger the alarm on holidays.</para>"
371 "<para>You can specify your holiday region in the Configuration dialog.</para>"));
372 connect(mExcludeHolidays
, &CheckBox::toggled
, this, &RecurrenceEdit::contentsChanged
);
373 vlayout
->addWidget(mExcludeHolidays
);
375 mWorkTimeOnly
= new CheckBox(i18nc("@option:check", "Only during working time"), mExceptionGroup
);
376 mWorkTimeOnly
->setReadOnly(mReadOnly
);
377 mWorkTimeOnly
->setWhatsThis(xi18nc("@info:whatsthis",
378 "<para>Only execute the alarm during working hours, on working days.</para>"
379 "<para>You can specify working days and hours in the Configuration dialog.</para>"));
380 connect(mWorkTimeOnly
, &CheckBox::toggled
, this, &RecurrenceEdit::contentsChanged
);
381 vlayout
->addWidget(mWorkTimeOnly
);
383 topLayout
->addStretch();
384 mNoEmitTypeChanged
= false;
387 /******************************************************************************
388 * Show or hide the exception controls.
390 void RecurrenceEdit::showMoreOptions(bool more
)
393 mExceptionGroup
->show();
395 mExceptionGroup
->hide();
399 /******************************************************************************
400 * Verify the consistency of the entered data.
401 * Reply = widget to receive focus on error, or 0 if no error.
403 QWidget
* RecurrenceEdit::checkData(const KDateTime
& startDateTime
, QString
& errorMessage
) const
405 if (mAtLoginButton
->isChecked())
407 const_cast<RecurrenceEdit
*>(this)->mCurrStartDateTime
= startDateTime
;
408 if (mEndDateButton
->isChecked())
410 // N.B. End date/time takes the same time spec as start date/time
411 QWidget
* errWidget
= Q_NULLPTR
;
412 bool noTime
= !mEndTimeEdit
->isEnabled();
413 QDate endDate
= mEndDateEdit
->date();
414 if (endDate
< startDateTime
.date())
415 errWidget
= mEndDateEdit
;
416 else if (!noTime
&& QDateTime(endDate
, mEndTimeEdit
->time()) < startDateTime
.dateTime())
417 errWidget
= mEndTimeEdit
;
420 errorMessage
= noTime
421 ? i18nc("@info", "End date is earlier than start date")
422 : i18nc("@info", "End date/time is earlier than start date/time");
428 return mRule
->validate(errorMessage
);
431 /******************************************************************************
432 * Called when a recurrence period radio button is clicked.
434 void RecurrenceEdit::periodClicked(QAbstractButton
* button
)
436 RepeatType oldType
= mRuleButtonType
;
437 bool none
= (button
== mNoneButton
);
438 bool atLogin
= (button
== mAtLoginButton
);
439 bool subdaily
= (button
== mSubDailyButton
);
443 mRuleButtonType
= NO_RECUR
;
448 mRuleButtonType
= AT_LOGIN
;
449 mEndDateButton
->setChecked(true);
453 mRule
= mSubDailyRule
;
454 mRuleButtonType
= SUBDAILY
;
456 else if (button
== mDailyButton
)
459 mRuleButtonType
= DAILY
;
462 else if (button
== mWeeklyButton
)
465 mRuleButtonType
= WEEKLY
;
468 else if (button
== mMonthlyButton
)
470 mRule
= mMonthlyRule
;
471 mRuleButtonType
= MONTHLY
;
472 mMonthlyShown
= true;
474 else if (button
== mYearlyButton
)
477 mRuleButtonType
= ANNUAL
;
483 if (mRuleButtonType
!= oldType
)
485 mRuleStack
->setCurrentWidget(mRule
? mRule
: mNoRule
);
486 if (oldType
== NO_RECUR
|| none
)
487 mRangeButtonBox
->setEnabled(!none
);
488 mExceptionGroup
->setEnabled(!(none
|| atLogin
));
489 mEndAnyTimeCheckBox
->setEnabled(atLogin
);
492 mNoEndDateButton
->setEnabled(!atLogin
);
493 mRepeatCountButton
->setEnabled(!atLogin
);
496 mSubRepetition
->setEnabled(!(none
|| atLogin
));
497 if (!mNoEmitTypeChanged
)
498 Q_EMIT
typeChanged(mRuleButtonType
);
502 void RecurrenceEdit::slotAnyTimeToggled(bool on
)
504 QAbstractButton
* button
= mRuleButtonGroup
->checkedButton();
505 mEndTimeEdit
->setEnabled((button
== mAtLoginButton
&& !on
)
506 || (button
== mSubDailyButton
&& mEndDateButton
->isChecked()));
509 /******************************************************************************
510 * Called when a recurrence range type radio button is clicked.
512 void RecurrenceEdit::rangeTypeClicked()
514 bool endDate
= mEndDateButton
->isChecked();
515 mEndDateEdit
->setEnabled(endDate
);
516 mEndTimeEdit
->setEnabled(endDate
517 && ((mAtLoginButton
->isChecked() && !mEndAnyTimeCheckBox
->isChecked())
518 || mSubDailyButton
->isChecked()));
519 bool repeatCount
= mRepeatCountButton
->isChecked();
520 mRepeatCountEntry
->setEnabled(repeatCount
);
521 mRepeatCountLabel
->setEnabled(repeatCount
);
524 void RecurrenceEdit::showEvent(QShowEvent
*)
527 mRule
->setFrequencyFocus();
529 mRuleButtonGroup
->checkedButton()->setFocus();
533 /******************************************************************************
534 * Return the sub-repetition interval and count within the recurrence, i.e. the
535 * number of repetitions after the main recurrence.
537 Repetition
RecurrenceEdit::subRepetition() const
539 return (mRuleButtonType
>= SUBDAILY
) ? mSubRepetition
->repetition() : Repetition();
542 /******************************************************************************
543 * Called when the Sub-Repetition button has been pressed to display the
544 * sub-repetition dialog.
545 * Alarm repetition has the following restrictions:
546 * 1) Not allowed for a repeat-at-login alarm
547 * 2) For a date-only alarm, the repeat interval must be a whole number of days.
548 * 3) The overall repeat duration must be less than the recurrence interval.
550 void RecurrenceEdit::setSubRepetition(int reminderMinutes
, bool dateOnly
)
553 switch (mRuleButtonType
)
555 case RecurrenceEdit::NO_RECUR
:
556 case RecurrenceEdit::AT_LOGIN
: // alarm repeat not allowed
559 default: // repeat duration must be less than recurrence interval
562 updateEvent(event
, false);
563 maxDuration
= event
.longestRecurrenceInterval().asSeconds()/60 - reminderMinutes
- 1;
567 mSubRepetition
->initialise(mSubRepetition
->repetition(), dateOnly
, maxDuration
);
568 mSubRepetition
->setEnabled(mRuleButtonType
>= SUBDAILY
&& maxDuration
);
571 /******************************************************************************
572 * Activate the sub-repetition dialog.
574 void RecurrenceEdit::activateSubRepetition()
576 mSubRepetition
->activate();
579 /******************************************************************************
580 * Called when the value of the repeat count field changes, to reset the
581 * minimum value to 1 if the value was 0.
583 void RecurrenceEdit::repeatCountChanged(int value
)
585 if (value
> 0 && mRepeatCountEntry
->minimum() == 0)
586 mRepeatCountEntry
->setMinimum(1);
589 /******************************************************************************
590 * Add the date entered in the exception date edit control to the list of
593 void RecurrenceEdit::addException()
595 if (!mExceptionDateEdit
|| !mExceptionDateEdit
->date().isValid())
597 QDate date
= mExceptionDateEdit
->date();
598 DateList::Iterator it
;
601 for (it
= mExceptionDates
.begin(); it
!= mExceptionDates
.end(); ++index
, ++it
)
605 insert
= (date
!= *it
);
611 mExceptionDates
.insert(it
, date
);
612 mExceptionDateList
->insertItem(index
, new QListWidgetItem(KLocale::global()->formatDate(date
)));
613 Q_EMIT
contentsChanged();
615 mExceptionDateList
->setCurrentItem(mExceptionDateList
->item(index
));
616 enableExceptionButtons();
619 /******************************************************************************
620 * Change the currently highlighted exception date to that entered in the
621 * exception date edit control.
623 void RecurrenceEdit::changeException()
625 if (!mExceptionDateEdit
|| !mExceptionDateEdit
->date().isValid())
627 QListWidgetItem
* item
= mExceptionDateList
->currentItem();
628 if (item
&& mExceptionDateList
->isItemSelected(item
))
630 int index
= mExceptionDateList
->row(item
);
631 QDate olddate
= mExceptionDates
[index
];
632 QDate newdate
= mExceptionDateEdit
->date();
633 if (newdate
!= olddate
)
635 mExceptionDates
.removeAt(index
);
636 mExceptionDateList
->takeItem(index
);
637 Q_EMIT
contentsChanged();
643 /******************************************************************************
644 * Delete the currently highlighted exception date.
646 void RecurrenceEdit::deleteException()
648 QListWidgetItem
* item
= mExceptionDateList
->currentItem();
649 if (item
&& mExceptionDateList
->isItemSelected(item
))
651 int index
= mExceptionDateList
->row(item
);
652 mExceptionDates
.removeAt(index
);
653 mExceptionDateList
->takeItem(index
);
654 Q_EMIT
contentsChanged();
655 enableExceptionButtons();
659 /******************************************************************************
660 * Enable/disable the exception group buttons according to whether any item is
661 * selected in the exceptions listbox.
663 void RecurrenceEdit::enableExceptionButtons()
665 QListWidgetItem
* item
= mExceptionDateList
->currentItem();
667 if (mDeleteExceptionButton
)
668 mDeleteExceptionButton
->setEnabled(enable
);
669 if (mChangeExceptionButton
)
670 mChangeExceptionButton
->setEnabled(enable
);
672 // Prevent the exceptions list box receiving keyboard focus is it's empty
673 mExceptionDateList
->setFocusPolicy(mExceptionDateList
->count() ? Qt::WheelFocus
: Qt::NoFocus
);
676 /******************************************************************************
677 * Notify this instance of a change in the alarm start date.
679 void RecurrenceEdit::setStartDate(const QDate
& start
, const QDate
& today
)
683 setRuleDefaults(start
);
686 mEndDateEdit
->setMinimumDate(today
);
687 if (mExceptionDateEdit
)
688 mExceptionDateEdit
->setMinimumDate(today
);
692 const QString startString
= i18nc("@info", "Date cannot be earlier than start date");
693 mEndDateEdit
->setMinimumDate(start
, startString
);
694 if (mExceptionDateEdit
)
695 mExceptionDateEdit
->setMinimumDate(start
, startString
);
700 /******************************************************************************
701 * Specify the default recurrence end date.
703 void RecurrenceEdit::setDefaultEndDate(const QDate
& end
)
705 if (!mEndDateButton
->isChecked())
706 mEndDateEdit
->setDate(end
);
709 void RecurrenceEdit::setEndDateTime(const KDateTime
& end
)
711 KDateTime edt
= end
.toTimeSpec(mCurrStartDateTime
.timeSpec());
712 mEndDateEdit
->setDate(edt
.date());
713 mEndTimeEdit
->setValue(edt
.time());
714 mEndTimeEdit
->setEnabled(!end
.isDateOnly());
715 mEndAnyTimeCheckBox
->setChecked(end
.isDateOnly());
718 KDateTime
RecurrenceEdit::endDateTime() const
720 if (mRuleButtonGroup
->checkedButton() == mAtLoginButton
&& mEndAnyTimeCheckBox
->isChecked())
721 return KDateTime(mEndDateEdit
->date(), mCurrStartDateTime
.timeSpec());
722 return KDateTime(mEndDateEdit
->date(), mEndTimeEdit
->time(), mCurrStartDateTime
.timeSpec());
725 /******************************************************************************
726 * Set all controls to their default values.
728 void RecurrenceEdit::setDefaults(const KDateTime
& from
)
730 mCurrStartDateTime
= from
;
731 QDate fromDate
= from
.date();
732 mNoEndDateButton
->setChecked(true);
734 mSubDailyRule
->setFrequency(1);
735 mDailyRule
->setFrequency(1);
736 mWeeklyRule
->setFrequency(1);
737 mMonthlyRule
->setFrequency(1);
738 mYearlyRule
->setFrequency(1);
740 setRuleDefaults(fromDate
);
741 mMonthlyRule
->setType(MonthYearRule::DATE
); // date in month
742 mYearlyRule
->setType(MonthYearRule::DATE
); // date in year
744 mEndDateEdit
->setDate(fromDate
);
746 mNoEmitTypeChanged
= true;
748 switch (Preferences::defaultRecurPeriod())
750 case AT_LOGIN
: button
= mAtLoginButton
; break;
751 case ANNUAL
: button
= mYearlyButton
; break;
752 case MONTHLY
: button
= mMonthlyButton
; break;
753 case WEEKLY
: button
= mWeeklyButton
; break;
754 case DAILY
: button
= mDailyButton
; break;
755 case SUBDAILY
: button
= mSubDailyButton
; break;
757 default: button
= mNoneButton
; break;
759 button
->setChecked(true);
760 mNoEmitTypeChanged
= false;
762 enableExceptionButtons();
767 /******************************************************************************
768 * Set the controls for weekly, monthly and yearly rules which have not so far
769 * been shown, to their default values, depending on the recurrence start date.
771 void RecurrenceEdit::setRuleDefaults(const QDate
& fromDate
)
773 int day
= fromDate
.day();
774 int dayOfWeek
= fromDate
.dayOfWeek();
775 int month
= fromDate
.month();
777 mDailyRule
->setDays(true);
779 mWeeklyRule
->setDay(dayOfWeek
);
781 mMonthlyRule
->setDefaultValues(day
, dayOfWeek
);
783 mYearlyRule
->setDefaultValues(day
, dayOfWeek
, month
);
786 /******************************************************************************
787 * Initialise the recurrence to select repeat-at-login.
788 * This function and set() are mutually exclusive: call one or the other, not both.
790 void RecurrenceEdit::setRepeatAtLogin()
792 mAtLoginButton
->setChecked(true);
793 mEndDateButton
->setChecked(true);
796 /******************************************************************************
797 * Set the state of all controls to reflect the data in the specified event.
799 void RecurrenceEdit::set(const KAEvent
& event
)
801 setDefaults(event
.mainDateTime().kDateTime());
802 if (event
.repeatAtLogin())
804 mAtLoginButton
->setChecked(true);
805 mEndDateButton
->setChecked(true);
808 mNoneButton
->setChecked(true);
809 KARecurrence
* recurrence
= event
.recurrence();
812 KARecurrence::Type rtype
= recurrence
->type();
815 case KARecurrence::MINUTELY
:
816 mSubDailyButton
->setChecked(true);
819 case KARecurrence::DAILY
:
821 mDailyButton
->setChecked(true);
822 QBitArray rDays
= recurrence
->days();
824 for (int i
= 0; i
< 7 && !set
; ++i
)
825 set
= rDays
.testBit(i
);
827 mDailyRule
->setDays(rDays
);
829 mDailyRule
->setDays(true);
832 case KARecurrence::WEEKLY
:
834 mWeeklyButton
->setChecked(true);
835 QBitArray rDays
= recurrence
->days();
836 mWeeklyRule
->setDays(rDays
);
839 case KARecurrence::MONTHLY_POS
: // on nth (Tuesday) of the month
841 QList
<RecurrenceRule::WDayPos
> posns
= recurrence
->monthPositions();
842 int i
= posns
.first().pos();
845 // It's every (Tuesday) of the month. Convert to a weekly recurrence
846 // (but ignoring any non-every xxxDay positions).
847 mWeeklyButton
->setChecked(true);
848 mWeeklyRule
->setFrequency(recurrence
->frequency());
850 for (int i
= 0, end
= posns
.count(); i
< end
; ++i
)
853 rDays
.setBit(posns
[i
].day() - 1, 1);
855 mWeeklyRule
->setDays(rDays
);
858 mMonthlyButton
->setChecked(true);
859 mMonthlyRule
->setPosition(i
, posns
.first().day());
862 case KARecurrence::MONTHLY_DAY
: // on nth day of the month
864 mMonthlyButton
->setChecked(true);
865 QList
<int> rmd
= recurrence
->monthDays();
866 int day
= (rmd
.isEmpty()) ? event
.mainDateTime().date().day() : rmd
.first();
867 mMonthlyRule
->setDate(day
);
870 case KARecurrence::ANNUAL_DATE
: // on the nth day of (months...) in the year
871 case KARecurrence::ANNUAL_POS
: // on the nth (Tuesday) of (months...) in the year
873 if (rtype
== KARecurrence::ANNUAL_DATE
)
875 mYearlyButton
->setChecked(true);
876 const QList
<int> rmd
= recurrence
->monthDays();
877 int day
= (rmd
.isEmpty()) ? event
.mainDateTime().date().day() : rmd
.first();
878 mYearlyRule
->setDate(day
);
879 mYearlyRule
->setFeb29Type(recurrence
->feb29Type());
881 else if (rtype
== KARecurrence::ANNUAL_POS
)
883 mYearlyButton
->setChecked(true);
884 QList
<RecurrenceRule::WDayPos
> posns
= recurrence
->yearPositions();
885 mYearlyRule
->setPosition(posns
.first().pos(), posns
.first().day());
887 mYearlyRule
->setMonths(recurrence
->yearMonths());
894 mRule
->setFrequency(recurrence
->frequency());
896 // Get range information
897 KDateTime endtime
= mCurrStartDateTime
;
898 int duration
= recurrence
->duration();
900 mNoEndDateButton
->setChecked(true);
903 mRepeatCountButton
->setChecked(true);
904 mRepeatCountEntry
->setValue(duration
);
908 mEndDateButton
->setChecked(true);
909 endtime
= recurrence
->endDateTime();
910 mEndTimeEdit
->setValue(endtime
.time());
912 mEndDateEdit
->setDate(endtime
.date());
914 // Get exception information
915 mExceptionDates
= event
.recurrence()->exDates();
916 qSort(mExceptionDates
);
917 mExceptionDateList
->clear();
918 for (int i
= 0, iend
= mExceptionDates
.count(); i
< iend
; ++i
)
919 new QListWidgetItem(KLocale::global()->formatDate(mExceptionDates
[i
]), mExceptionDateList
);
920 enableExceptionButtons();
921 mExcludeHolidays
->setChecked(event
.holidaysExcluded());
922 mWorkTimeOnly
->setChecked(event
.workTimeOnly());
924 // Get repetition within recurrence
925 mSubRepetition
->set(event
.repetition());
932 /******************************************************************************
933 * Update the specified KAEvent with the entered recurrence data.
934 * If 'adjustStart' is true, the start date/time will be adjusted if necessary
935 * to be the first date/time which recurs on or after the original start.
937 void RecurrenceEdit::updateEvent(KAEvent
& event
, bool adjustStart
)
939 // Get end date and repeat count, common to all types of recurring events
943 if (mNoEndDateButton
->isChecked())
945 else if (mRepeatCountButton
->isChecked())
946 repeatCount
= mRepeatCountEntry
->value();
950 endDate
= mEndDateEdit
->date();
951 endTime
= mEndTimeEdit
->time();
954 // Set up the recurrence according to the type selected
955 event
.startChanges();
956 QAbstractButton
* button
= mRuleButtonGroup
->checkedButton();
957 event
.setRepeatAtLogin(button
== mAtLoginButton
);
958 int frequency
= mRule
? mRule
->frequency() : 0;
959 if (button
== mSubDailyButton
)
961 KDateTime
endDateTime(endDate
, endTime
, mCurrStartDateTime
.timeSpec());
962 event
.setRecurMinutely(frequency
, repeatCount
, endDateTime
);
964 else if (button
== mDailyButton
)
966 event
.setRecurDaily(frequency
, mDailyRule
->days(), repeatCount
, endDate
);
968 else if (button
== mWeeklyButton
)
970 event
.setRecurWeekly(frequency
, mWeeklyRule
->days(), repeatCount
, endDate
);
972 else if (button
== mMonthlyButton
)
974 if (mMonthlyRule
->type() == MonthlyRule::POS
)
977 KAEvent::MonthPos pos
;
978 pos
.days
.fill(false);
979 pos
.days
.setBit(mMonthlyRule
->dayOfWeek() - 1);
980 pos
.weeknum
= mMonthlyRule
->week();
981 QVector
<KAEvent::MonthPos
> poses(1, pos
);
982 event
.setRecurMonthlyByPos(frequency
, poses
, repeatCount
, endDate
);
987 int daynum
= mMonthlyRule
->date();
988 QVector
<int> daynums(1, daynum
);
989 event
.setRecurMonthlyByDate(frequency
, daynums
, repeatCount
, endDate
);
992 else if (button
== mYearlyButton
)
994 QVector
<int> months
= mYearlyRule
->months();
995 if (mYearlyRule
->type() == YearlyRule::POS
)
998 KAEvent::MonthPos pos
;
999 pos
.days
.fill(false);
1000 pos
.days
.setBit(mYearlyRule
->dayOfWeek() - 1);
1001 pos
.weeknum
= mYearlyRule
->week();
1002 QVector
<KAEvent::MonthPos
> poses(1, pos
);
1003 event
.setRecurAnnualByPos(frequency
, poses
, months
, repeatCount
, endDate
);
1007 // It's by date in month
1008 event
.setRecurAnnualByDate(frequency
, months
, mYearlyRule
->date(),
1009 mYearlyRule
->feb29Type(), repeatCount
, endDate
);
1018 if (!event
.recurs())
1021 return; // an error occurred setting up the recurrence
1024 event
.setFirstRecurrence();
1026 // Set up repetition within the recurrence
1027 // N.B. This requires the main recurrence to be set up first.
1028 event
.setRepetition((mRuleButtonType
< SUBDAILY
) ? Repetition() : mSubRepetition
->repetition());
1030 // Set up exceptions
1031 event
.recurrence()->setExDates(mExceptionDates
);
1032 event
.setWorkTimeOnly(mWorkTimeOnly
->isChecked());
1033 event
.setExcludeHolidays(mExcludeHolidays
->isChecked());
1038 /******************************************************************************
1039 * Save the state of all controls.
1041 void RecurrenceEdit::saveState()
1043 mSavedRuleButton
= mRuleButtonGroup
->checkedButton();
1046 mSavedRangeButton
= mRangeButtonGroup
->checkedButton();
1047 if (mSavedRangeButton
== mRepeatCountButton
)
1048 mSavedRecurCount
= mRepeatCountEntry
->value();
1049 else if (mSavedRangeButton
== mEndDateButton
)
1051 mSavedEndDateTime
= KDateTime(QDateTime(mEndDateEdit
->date(), mEndTimeEdit
->time()), mCurrStartDateTime
.timeSpec());
1052 mSavedEndDateTime
.setDateOnly(mEndAnyTimeCheckBox
->isChecked());
1054 mSavedExceptionDates
= mExceptionDates
;
1055 mSavedWorkTimeOnly
= mWorkTimeOnly
->isChecked();
1056 mSavedExclHolidays
= mExcludeHolidays
->isChecked();
1057 mSavedRepetition
= mSubRepetition
->repetition();
1060 /******************************************************************************
1061 * Check whether any of the controls have changed state since initialisation.
1063 bool RecurrenceEdit::stateChanged() const
1065 if (mSavedRuleButton
!= mRuleButtonGroup
->checkedButton()
1066 || mSavedRangeButton
!= mRangeButtonGroup
->checkedButton()
1067 || (mRule
&& mRule
->stateChanged()))
1069 if (mSavedRangeButton
== mRepeatCountButton
1070 && mSavedRecurCount
!= mRepeatCountEntry
->value())
1072 if (mSavedRangeButton
== mEndDateButton
)
1074 KDateTime
edt(QDateTime(mEndDateEdit
->date(), mEndTimeEdit
->time()), mCurrStartDateTime
.timeSpec());
1075 edt
.setDateOnly(mEndAnyTimeCheckBox
->isChecked());
1076 if (mSavedEndDateTime
!= edt
)
1079 if (mSavedExceptionDates
!= mExceptionDates
1080 || mSavedWorkTimeOnly
!= mWorkTimeOnly
->isChecked()
1081 || mSavedExclHolidays
!= mExcludeHolidays
->isChecked()
1082 || mSavedRepetition
!= mSubRepetition
->repetition())
1089 /*=============================================================================
1091 = Base class for rule widgets, including recurrence frequency.
1092 =============================================================================*/
1094 Rule::Rule(const QString
& freqText
, const QString
& freqWhatsThis
, bool time
, bool readOnly
, QWidget
* parent
)
1097 mLayout
= new QVBoxLayout(this);
1098 mLayout
->setMargin(0);
1099 mLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1101 QHBoxLayout
* freqLayout
= new QHBoxLayout();
1102 freqLayout
->setMargin(0);
1103 freqLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1104 mLayout
->addLayout(freqLayout
);
1105 QWidget
* box
= new QWidget(this); // this is to control the QWhatsThis text display area
1106 freqLayout
->addWidget(box
, 0, Qt::AlignLeft
);
1107 QHBoxLayout
* boxLayout
= new QHBoxLayout(box
);
1108 boxLayout
->setMargin(0);
1110 QLabel
* label
= new QLabel(i18nc("@label:spinbox", "Recur e&very"), box
);
1111 label
->setFixedSize(label
->sizeHint());
1112 boxLayout
->addWidget(label
, 0, Qt::AlignLeft
);
1115 mIntSpinBox
= Q_NULLPTR
;
1116 mSpinBox
= mTimeSpinBox
= new TimeSpinBox(1, 5999, box
);
1117 mTimeSpinBox
->setFixedSize(mTimeSpinBox
->sizeHint());
1118 mTimeSpinBox
->setReadOnly(readOnly
);
1119 boxLayout
->addWidget(mSpinBox
, 0, Qt::AlignLeft
);
1123 mTimeSpinBox
= Q_NULLPTR
;
1124 mSpinBox
= mIntSpinBox
= new SpinBox(1, 999, box
);
1125 mIntSpinBox
->setFixedSize(mIntSpinBox
->sizeHint());
1126 mIntSpinBox
->setReadOnly(readOnly
);
1127 boxLayout
->addWidget(mSpinBox
, 0, Qt::AlignLeft
);
1129 connect(mSpinBox
, SIGNAL(valueChanged(int)), SIGNAL(frequencyChanged()));
1130 connect(mSpinBox
, SIGNAL(valueChanged(int)), SIGNAL(changed()));
1131 label
->setBuddy(mSpinBox
);
1132 label
= new QLabel(freqText
, box
);
1133 label
->setFixedSize(label
->sizeHint());
1134 boxLayout
->addWidget(label
, 0, Qt::AlignLeft
);
1135 box
->setFixedSize(sizeHint());
1136 box
->setWhatsThis(freqWhatsThis
);
1139 int Rule::frequency() const
1142 return mIntSpinBox
->value();
1144 return mTimeSpinBox
->value();
1148 void Rule::setFrequency(int n
)
1151 mIntSpinBox
->setValue(n
);
1153 mTimeSpinBox
->setValue(n
);
1156 /******************************************************************************
1157 * Save the state of all controls.
1159 void Rule::saveState()
1161 mSavedFrequency
= frequency();
1164 /******************************************************************************
1165 * Check whether any of the controls have changed state since initialisation.
1167 bool Rule::stateChanged() const
1169 return (mSavedFrequency
!= frequency());
1173 /*=============================================================================
1174 = Class SubDailyRule
1175 = Sub-daily rule widget.
1176 =============================================================================*/
1178 SubDailyRule::SubDailyRule(bool readOnly
, QWidget
* parent
)
1179 : Rule(i18nc("@label Time units for user-entered numbers", "hours:minutes"),
1180 i18nc("@info:whatsthis", "Enter the number of hours and minutes between repetitions of the alarm"),
1181 true, readOnly
, parent
)
1185 /*=============================================================================
1187 = Daily/weekly rule widget base class.
1188 =============================================================================*/
1190 DayWeekRule::DayWeekRule(const QString
& freqText
, const QString
& freqWhatsThis
, const QString
& daysWhatsThis
,
1191 bool readOnly
, QWidget
* parent
)
1192 : Rule(freqText
, freqWhatsThis
, false, readOnly
, parent
),
1195 QGridLayout
* grid
= new QGridLayout();
1197 grid
->setRowStretch(0, 1);
1198 layout()->addLayout(grid
);
1200 QLabel
* label
= new QLabel(i18nc("@label On: Tuesday", "O&n:"), this);
1201 label
->setFixedSize(label
->sizeHint());
1202 grid
->addWidget(label
, 0, 0, Qt::AlignRight
| Qt::AlignTop
);
1203 grid
->setColumnMinimumWidth(1, style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1205 // List the days of the week starting at the user's start day of the week.
1206 // Save the first day of the week, just in case it changes while the dialog is open.
1207 QWidget
* box
= new QWidget(this); // this is to control the QWhatsThis text display area
1208 QGridLayout
* dgrid
= new QGridLayout(box
);
1209 dgrid
->setMargin(0);
1210 dgrid
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1211 const KCalendarSystem
* calendar
= KLocale::global()->calendar();
1212 for (int i
= 0; i
< 7; ++i
)
1214 int day
= KAlarm::localeDayInWeek_to_weekDay(i
);
1215 mDayBox
[i
] = new CheckBox(calendar
->weekDayName(day
), box
);
1216 mDayBox
[i
]->setFixedSize(mDayBox
[i
]->sizeHint());
1217 mDayBox
[i
]->setReadOnly(readOnly
);
1218 connect(mDayBox
[i
], &QAbstractButton::toggled
, this, &Rule::changed
);
1219 dgrid
->addWidget(mDayBox
[i
], i
%4, i
/4, Qt::AlignLeft
);
1221 box
->setFixedSize(box
->sizeHint());
1222 box
->setWhatsThis(daysWhatsThis
);
1223 grid
->addWidget(box
, 0, 2, Qt::AlignLeft
);
1224 label
->setBuddy(mDayBox
[0]);
1225 grid
->setColumnStretch(3, 1);
1228 /******************************************************************************
1229 * Fetch which days of the week have been ticked.
1231 QBitArray
DayWeekRule::days() const
1235 for (int i
= 0; i
< 7; ++i
)
1236 if (mDayBox
[i
]->isChecked())
1237 ds
.setBit(KAlarm::localeDayInWeek_to_weekDay(i
) - 1, 1);
1241 /******************************************************************************
1242 * Tick/untick every day of the week.
1244 void DayWeekRule::setDays(bool tick
)
1246 for (int i
= 0; i
< 7; ++i
)
1247 mDayBox
[i
]->setChecked(tick
);
1250 /******************************************************************************
1251 * Tick/untick each day of the week according to the specified bits.
1253 void DayWeekRule::setDays(const QBitArray
& days
)
1255 for (int i
= 0; i
< 7; ++i
)
1257 bool x
= days
.testBit(KAlarm::localeDayInWeek_to_weekDay(i
) - 1);
1258 mDayBox
[i
]->setChecked(x
);
1262 /******************************************************************************
1263 * Tick the specified day of the week, and untick all other days.
1265 void DayWeekRule::setDay(int dayOfWeek
)
1267 for (int i
= 0; i
< 7; ++i
)
1268 mDayBox
[i
]->setChecked(false);
1269 if (dayOfWeek
> 0 && dayOfWeek
<= 7)
1270 mDayBox
[KAlarm::weekDay_to_localeDayInWeek(dayOfWeek
)]->setChecked(true);
1273 /******************************************************************************
1274 * Validate: check that at least one day is selected.
1276 QWidget
* DayWeekRule::validate(QString
& errorMessage
)
1278 for (int i
= 0; i
< 7; ++i
)
1279 if (mDayBox
[i
]->isChecked())
1281 errorMessage
= i18nc("@info", "No day selected");
1285 /******************************************************************************
1286 * Save the state of all controls.
1288 void DayWeekRule::saveState()
1291 mSavedDays
= days();
1294 /******************************************************************************
1295 * Check whether any of the controls have changed state since initialisation.
1297 bool DayWeekRule::stateChanged() const
1299 return (Rule::stateChanged()
1300 || mSavedDays
!= days());
1304 /*=============================================================================
1306 = Daily rule widget.
1307 =============================================================================*/
1309 DailyRule::DailyRule(bool readOnly
, QWidget
* parent
)
1310 : DayWeekRule(i18nc("@label Time unit for user-entered number", "day(s)"),
1311 i18nc("@info:whatsthis", "Enter the number of days between repetitions of the alarm"),
1312 i18nc("@info:whatsthis", "Select the days of the week on which the alarm is allowed to occur"),
1317 /*=============================================================================
1319 = Weekly rule widget.
1320 =============================================================================*/
1322 WeeklyRule::WeeklyRule(bool readOnly
, QWidget
* parent
)
1323 : DayWeekRule(i18nc("@label Time unit for user-entered number", "week(s)"),
1324 i18nc("@info:whatsthis", "Enter the number of weeks between repetitions of the alarm"),
1325 i18nc("@info:whatsthis", "Select the days of the week on which to repeat the alarm"),
1330 /*=============================================================================
1331 = Class MonthYearRule
1332 = Monthly/yearly rule widget base class.
1333 =============================================================================*/
1335 MonthYearRule::MonthYearRule(const QString
& freqText
, const QString
& freqWhatsThis
, bool allowEveryWeek
,
1336 bool readOnly
, QWidget
* parent
)
1337 : Rule(freqText
, freqWhatsThis
, false, readOnly
, parent
),
1338 mEveryWeek(allowEveryWeek
)
1340 mButtonGroup
= new ButtonGroup(this);
1342 // Month day selector
1343 QGridLayout
* boxLayout
= new QGridLayout();
1344 boxLayout
->setMargin(0);
1345 boxLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1346 layout()->addLayout(boxLayout
);
1348 mDayButton
= new RadioButton(i18nc("@option:radio On day number in the month", "O&n day"), this);
1349 mDayButton
->setFixedSize(mDayButton
->sizeHint());
1350 mDayButton
->setReadOnly(readOnly
);
1351 mButtonGroup
->addButton(mDayButton
);
1352 mDayButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm on the selected day of the month"));
1353 boxLayout
->addWidget(mDayButton
, 0, 0);
1355 mDayCombo
= new ComboBox(this);
1356 mDayCombo
->setEditable(false);
1357 mDayCombo
->setMaxVisibleItems(11);
1358 for (int i
= 0; i
< 31; ++i
)
1359 mDayCombo
->addItem(QString::number(i
+ 1));
1360 mDayCombo
->addItem(i18nc("@item:inlistbox Last day of month", "Last"));
1361 mDayCombo
->setFixedSize(mDayCombo
->sizeHint());
1362 mDayCombo
->setReadOnly(readOnly
);
1363 mDayCombo
->setWhatsThis(i18nc("@info:whatsthis", "Select the day of the month on which to repeat the alarm"));
1364 mDayButton
->setFocusWidget(mDayCombo
);
1365 connect(mDayCombo
, static_cast<void (ComboBox::*)(int)>(&ComboBox::activated
), this, &MonthYearRule::slotDaySelected
);
1366 connect(mDayCombo
, static_cast<void (ComboBox::*)(int)>(&ComboBox::currentIndexChanged
), this, &MonthYearRule::changed
);
1367 boxLayout
->addWidget(mDayCombo
, 0, 1, 1, 2, Qt::AlignLeft
);
1369 // Month position selector
1370 mPosButton
= new RadioButton(i18nc("@option:radio On the 1st Tuesday", "On t&he"), this);
1371 mPosButton
->setFixedSize(mPosButton
->sizeHint());
1372 mPosButton
->setReadOnly(readOnly
);
1373 mButtonGroup
->addButton(mPosButton
);
1374 mPosButton
->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm on one day of the week, in the selected week of the month"));
1375 boxLayout
->addWidget(mPosButton
, 1, 0);
1377 mWeekCombo
= new ComboBox(this);
1378 mWeekCombo
->setEditable(false);
1379 mWeekCombo
->addItem(i18nc("@item:inlistbox", "1st"));
1380 mWeekCombo
->addItem(i18nc("@item:inlistbox", "2nd"));
1381 mWeekCombo
->addItem(i18nc("@item:inlistbox", "3rd"));
1382 mWeekCombo
->addItem(i18nc("@item:inlistbox", "4th"));
1383 mWeekCombo
->addItem(i18nc("@item:inlistbox", "5th"));
1384 mWeekCombo
->addItem(i18nc("@item:inlistbox Last Monday in March", "Last"));
1385 mWeekCombo
->addItem(i18nc("@item:inlistbox", "2nd Last"));
1386 mWeekCombo
->addItem(i18nc("@item:inlistbox", "3rd Last"));
1387 mWeekCombo
->addItem(i18nc("@item:inlistbox", "4th Last"));
1388 mWeekCombo
->addItem(i18nc("@item:inlistbox", "5th Last"));
1391 mWeekCombo
->addItem(i18nc("@item:inlistbox Every (Monday...) in month", "Every"));
1392 mWeekCombo
->setMaxVisibleItems(11);
1394 mWeekCombo
->setWhatsThis(i18nc("@info:whatsthis", "Select the week of the month in which to repeat the alarm"));
1395 mWeekCombo
->setFixedSize(mWeekCombo
->sizeHint());
1396 mWeekCombo
->setReadOnly(readOnly
);
1397 mPosButton
->setFocusWidget(mWeekCombo
);
1398 connect(mWeekCombo
, static_cast<void (ComboBox::*)(int)>(&ComboBox::currentIndexChanged
), this, &MonthYearRule::changed
);
1399 boxLayout
->addWidget(mWeekCombo
, 1, 1);
1401 mDayOfWeekCombo
= new ComboBox(this);
1402 mDayOfWeekCombo
->setEditable(false);
1403 const KCalendarSystem
* calendar
= KLocale::global()->calendar();
1404 for (int i
= 0; i
< 7; ++i
)
1406 int day
= KAlarm::localeDayInWeek_to_weekDay(i
);
1407 mDayOfWeekCombo
->addItem(calendar
->weekDayName(day
));
1409 mDayOfWeekCombo
->setReadOnly(readOnly
);
1410 mDayOfWeekCombo
->setWhatsThis(i18nc("@info:whatsthis", "Select the day of the week on which to repeat the alarm"));
1411 connect(mDayOfWeekCombo
, static_cast<void (ComboBox::*)(int)>(&ComboBox::currentIndexChanged
), this, &MonthYearRule::changed
);
1412 boxLayout
->addWidget(mDayOfWeekCombo
, 1, 2, Qt::AlignLeft
);
1414 connect(mButtonGroup
, &ButtonGroup::buttonSet
, this, &MonthYearRule::clicked
);
1415 connect(mButtonGroup
, &ButtonGroup::buttonSet
, this, &MonthYearRule::changed
);
1418 MonthYearRule::DayPosType
MonthYearRule::type() const
1420 return (mButtonGroup
->checkedButton() == mDayButton
) ? DATE
: POS
;
1423 void MonthYearRule::setType(MonthYearRule::DayPosType type
)
1426 mDayButton
->setChecked(true);
1428 mPosButton
->setChecked(true);
1431 void MonthYearRule::setDefaultValues(int dayOfMonth
, int dayOfWeek
)
1434 mDayCombo
->setCurrentIndex(dayOfMonth
);
1435 mWeekCombo
->setCurrentIndex(dayOfMonth
/ 7);
1436 mDayOfWeekCombo
->setCurrentIndex(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek
));
1439 int MonthYearRule::date() const
1441 int daynum
= mDayCombo
->currentIndex() + 1;
1442 return (daynum
<= 31) ? daynum
: 31 - daynum
;
1445 int MonthYearRule::week() const
1447 int weeknum
= mWeekCombo
->currentIndex() + 1;
1448 return (weeknum
<= 5) ? weeknum
: (weeknum
== 11) ? 0 : 5 - weeknum
;
1451 int MonthYearRule::dayOfWeek() const
1453 return KAlarm::localeDayInWeek_to_weekDay(mDayOfWeekCombo
->currentIndex());
1456 void MonthYearRule::setDate(int dayOfMonth
)
1458 mDayButton
->setChecked(true);;
1459 mDayCombo
->setCurrentIndex(dayOfMonth
> 0 ? dayOfMonth
- 1 : dayOfMonth
< 0 ? 30 - dayOfMonth
: 0); // day 0 shouldn't ever occur
1462 void MonthYearRule::setPosition(int week
, int dayOfWeek
)
1464 mPosButton
->setChecked(true);
1465 mWeekCombo
->setCurrentIndex((week
> 0) ? week
- 1 : (week
< 0) ? 4 - week
: mEveryWeek
? 10 : 0);
1466 mDayOfWeekCombo
->setCurrentIndex(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek
));
1469 void MonthYearRule::enableSelection(DayPosType type
)
1471 bool date
= (type
== DATE
);
1472 mDayCombo
->setEnabled(date
);
1473 mWeekCombo
->setEnabled(!date
);
1474 mDayOfWeekCombo
->setEnabled(!date
);
1477 void MonthYearRule::clicked(QAbstractButton
* button
)
1479 enableSelection(button
== mDayButton
? DATE
: POS
);
1482 void MonthYearRule::slotDaySelected(int index
)
1484 daySelected(index
<= 30 ? index
+ 1 : 30 - index
);
1487 /******************************************************************************
1488 * Save the state of all controls.
1490 void MonthYearRule::saveState()
1493 mSavedType
= type();
1494 if (mSavedType
== DATE
)
1498 mSavedWeek
= week();
1499 mSavedWeekDay
= dayOfWeek();
1503 /******************************************************************************
1504 * Check whether any of the controls have changed state since initialisation.
1506 bool MonthYearRule::stateChanged() const
1508 if (Rule::stateChanged()
1509 || mSavedType
!= type())
1511 if (mSavedType
== DATE
)
1513 if (mSavedDay
!= date())
1518 if (mSavedWeek
!= week()
1519 || mSavedWeekDay
!= dayOfWeek())
1526 /*=============================================================================
1528 = Monthly rule widget.
1529 =============================================================================*/
1531 MonthlyRule::MonthlyRule(bool readOnly
, QWidget
* parent
)
1532 : MonthYearRule(i18nc("@label Time unit for user-entered number", "month(s)"),
1533 i18nc("@info:whatsthis", "Enter the number of months between repetitions of the alarm"),
1534 false, readOnly
, parent
)
1538 /*=============================================================================
1540 = Yearly rule widget.
1541 =============================================================================*/
1543 YearlyRule::YearlyRule(bool readOnly
, QWidget
* parent
)
1544 : MonthYearRule(i18nc("@label Time unit for user-entered number", "year(s)"),
1545 i18nc("@info:whatsthis", "Enter the number of years between repetitions of the alarm"),
1546 true, readOnly
, parent
)
1548 // Set up the month selection widgets
1549 QHBoxLayout
* hlayout
= new QHBoxLayout();
1550 hlayout
->setMargin(0);
1551 layout()->addLayout(hlayout
);
1552 QLabel
* label
= new QLabel(i18nc("@label List of months to select", "Months:"), this);
1553 label
->setFixedSize(label
->sizeHint());
1554 hlayout
->addWidget(label
, 0, Qt::AlignLeft
| Qt::AlignTop
);
1556 // List the months of the year.
1557 QWidget
* w
= new QWidget(this); // this is to control the QWhatsThis text display area
1558 hlayout
->addWidget(w
, 1, Qt::AlignLeft
);
1559 QGridLayout
* grid
= new QGridLayout(w
);
1561 grid
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1562 const KCalendarSystem
* calendar
= KLocale::global()->calendar();
1563 int year
= KDateTime::currentLocalDate().year();
1564 for (int i
= 0; i
< 12; ++i
)
1566 mMonthBox
[i
] = new CheckBox(calendar
->monthName(i
+ 1, year
, KCalendarSystem::ShortName
), w
);
1567 mMonthBox
[i
]->setFixedSize(mMonthBox
[i
]->sizeHint());
1568 mMonthBox
[i
]->setReadOnly(readOnly
);
1569 connect(mMonthBox
[i
], &QAbstractButton::toggled
, this, &Rule::changed
);
1570 grid
->addWidget(mMonthBox
[i
], i
%3, i
/3, Qt::AlignLeft
);
1572 connect(mMonthBox
[1], &QAbstractButton::toggled
, this, &YearlyRule::enableFeb29
);
1573 w
->setFixedHeight(w
->sizeHint().height());
1574 w
->setWhatsThis(i18nc("@info:whatsthis", "Select the months of the year in which to repeat the alarm"));
1576 // February 29th handling option
1577 QHBoxLayout
* f29box
= new QHBoxLayout(this);
1578 layout()->addLayout(f29box
);
1579 w
= new QWidget(this); // this is to control the QWhatsThis text display area
1580 f29box
->addWidget(w
, 0, Qt::AlignLeft
);
1581 QHBoxLayout
* boxLayout
= new QHBoxLayout(w
);
1582 boxLayout
->setMargin(0);
1583 boxLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
1584 mFeb29Label
= new QLabel(i18nc("@label:listbox", "February 2&9th alarm in non-leap years:"));
1585 mFeb29Label
->setFixedSize(mFeb29Label
->sizeHint());
1586 boxLayout
->addWidget(mFeb29Label
);
1587 mFeb29Combo
= new ComboBox();
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
, static_cast<void (ComboBox::*)(int)>(&ComboBox::currentIndexChanged
), this, &YearlyRule::changed
);
1595 mFeb29Label
->setBuddy(mFeb29Combo
);
1596 boxLayout
->addWidget(mFeb29Combo
);
1597 w
->setFixedSize(w
->sizeHint());
1598 w
->setWhatsThis(i18nc("@info:whatsthis", "Select which date, if any, the February 29th alarm should trigger in non-leap years"));
1601 void YearlyRule::setDefaultValues(int dayOfMonth
, int dayOfWeek
, int month
)
1603 MonthYearRule::setDefaultValues(dayOfMonth
, dayOfWeek
);
1605 for (int i
= 0; i
< 12; ++i
)
1606 mMonthBox
[i
]->setChecked(i
== month
);
1607 setFeb29Type(KARecurrence::defaultFeb29Type());
1608 daySelected(dayOfMonth
); // enable/disable month checkboxes as appropriate
1611 /******************************************************************************
1612 * Fetch which months have been checked (1 - 12).
1613 * Reply = true if February has been checked.
1615 QVector
<int> YearlyRule::months() const
1618 for (int i
= 0; i
< 12; ++i
)
1619 if (mMonthBox
[i
]->isChecked() && mMonthBox
[i
]->isEnabled())
1620 mnths
.append(i
+ 1);
1624 /******************************************************************************
1625 * Check/uncheck each month of the year according to the specified list.
1627 void YearlyRule::setMonths(const QList
<int>& mnths
)
1630 for (int i
= 0; i
< 12; ++i
)
1632 for (int i
= 0, end
= mnths
.count(); i
< end
; ++i
)
1633 checked
[mnths
[i
] - 1] = true;
1634 for (int i
= 0; i
< 12; ++i
)
1635 mMonthBox
[i
]->setChecked(checked
[i
]);
1639 /******************************************************************************
1640 * Return the date for February 29th alarms in non-leap years.
1642 KARecurrence::Feb29Type
YearlyRule::feb29Type() const
1644 if (mFeb29Combo
->isEnabled())
1646 switch (mFeb29Combo
->currentIndex())
1648 case 1: return KARecurrence::Feb29_Mar1
;
1649 case 2: return KARecurrence::Feb29_Feb28
;
1653 return KARecurrence::Feb29_None
;
1656 /******************************************************************************
1657 * Set the date for February 29th alarms to trigger in non-leap years.
1659 void YearlyRule::setFeb29Type(KARecurrence::Feb29Type type
)
1665 case KARecurrence::Feb29_None
: index
= 0; break;
1666 case KARecurrence::Feb29_Mar1
: index
= 1; break;
1667 case KARecurrence::Feb29_Feb28
: index
= 2; break;
1669 mFeb29Combo
->setCurrentIndex(index
);
1672 /******************************************************************************
1673 * Validate: check that at least one month is selected.
1675 QWidget
* YearlyRule::validate(QString
& errorMessage
)
1677 for (int i
= 0; i
< 12; ++i
)
1678 if (mMonthBox
[i
]->isChecked() && mMonthBox
[i
]->isEnabled())
1680 errorMessage
= i18nc("@info", "No month selected");
1681 return mMonthBox
[0];
1684 /******************************************************************************
1685 * Called when a yearly recurrence type radio button is clicked,
1686 * to enable/disable month checkboxes as appropriate for the date selected.
1688 void YearlyRule::clicked(QAbstractButton
* button
)
1690 MonthYearRule::clicked(button
);
1691 daySelected(buttonType(button
) == DATE
? date() : 1);
1694 /******************************************************************************
1695 * Called when a day of the month is selected in a yearly recurrence, to
1696 * disable months for which the day is out of range.
1698 void YearlyRule::daySelected(int day
)
1700 mMonthBox
[1]->setEnabled(day
<= 29); // February
1701 bool enable
= (day
!= 31);
1702 mMonthBox
[3]->setEnabled(enable
); // April
1703 mMonthBox
[5]->setEnabled(enable
); // June
1704 mMonthBox
[8]->setEnabled(enable
); // September
1705 mMonthBox
[10]->setEnabled(enable
); // November
1709 /******************************************************************************
1710 * Enable/disable the February 29th combo box depending on whether February
1713 void YearlyRule::enableFeb29()
1715 bool enable
= (type() == DATE
&& date() == 29 && mMonthBox
[1]->isChecked() && mMonthBox
[1]->isEnabled());
1716 mFeb29Label
->setEnabled(enable
);
1717 mFeb29Combo
->setEnabled(enable
);
1720 /******************************************************************************
1721 * Save the state of all controls.
1723 void YearlyRule::saveState()
1725 MonthYearRule::saveState();
1726 mSavedMonths
= months();
1727 mSavedFeb29Type
= feb29Type();
1730 /******************************************************************************
1731 * Check whether any of the controls have changed state since initialisation.
1733 bool YearlyRule::stateChanged() const
1735 return (MonthYearRule::stateChanged()
1736 || mSavedMonths
!= months()
1737 || mSavedFeb29Type
!= feb29Type());